diff options
34 files changed, 2638 insertions, 1405 deletions
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e01aa5fc..bd1037f4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml | |||
| @@ -41,11 +41,11 @@ jobs: | |||
| 41 | 41 | ||
| 42 | steps: | 42 | steps: |
| 43 | - name: Checkout repository | 43 | - name: Checkout repository |
| 44 | uses: actions/checkout@v5 | 44 | uses: actions/checkout@v6 |
| 45 | 45 | ||
| 46 | # Initializes the CodeQL tools for scanning. | 46 | # Initializes the CodeQL tools for scanning. |
| 47 | - name: Initialize CodeQL | 47 | - name: Initialize CodeQL |
| 48 | uses: github/codeql-action/init@v3 | 48 | uses: github/codeql-action/init@v4 |
| 49 | with: | 49 | with: |
| 50 | languages: ${{ matrix.language }} | 50 | languages: ${{ matrix.language }} |
| 51 | # If you wish to specify custom queries, you can do so here or in a config file. | 51 | # If you wish to specify custom queries, you can do so here or in a config file. |
| @@ -82,4 +82,4 @@ jobs: | |||
| 82 | make | 82 | make |
| 83 | 83 | ||
| 84 | - name: Perform CodeQL Analysis | 84 | - name: Perform CodeQL Analysis |
| 85 | uses: github/codeql-action/analyze@v3 | 85 | uses: github/codeql-action/analyze@v4 |
diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index 14b82781..f19cc920 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml | |||
| @@ -18,7 +18,7 @@ jobs: | |||
| 18 | runs-on: ubuntu-latest | 18 | runs-on: ubuntu-latest |
| 19 | steps: | 19 | steps: |
| 20 | - name: Checkout | 20 | - name: Checkout |
| 21 | uses: actions/checkout@v5 | 21 | uses: actions/checkout@v6 |
| 22 | - name: Codespell | 22 | - name: Codespell |
| 23 | uses: codespell-project/actions-codespell@v2 | 23 | uses: codespell-project/actions-codespell@v2 |
| 24 | with: | 24 | with: |
diff --git a/.github/workflows/test-next.yml b/.github/workflows/test-next.yml index 0e69c251..a7e9b9d6 100644 --- a/.github/workflows/test-next.yml +++ b/.github/workflows/test-next.yml | |||
| @@ -30,7 +30,7 @@ jobs: | |||
| 30 | prepare: .github/prepare_debian.sh | 30 | prepare: .github/prepare_debian.sh |
| 31 | steps: | 31 | steps: |
| 32 | - name: Git clone repository | 32 | - name: Git clone repository |
| 33 | uses: actions/checkout@v5 | 33 | uses: actions/checkout@v6 |
| 34 | - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate | 34 | - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate |
| 35 | uses: mxschmitt/action-tmate@v3 | 35 | uses: mxschmitt/action-tmate@v3 |
| 36 | if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} | 36 | if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} |
| @@ -68,7 +68,7 @@ jobs: | |||
| 68 | - {"distro": "fedora:rawhide", "build": ".github/mock.sh"} | 68 | - {"distro": "fedora:rawhide", "build": ".github/mock.sh"} |
| 69 | steps: | 69 | steps: |
| 70 | - name: Git clone repository | 70 | - name: Git clone repository |
| 71 | uses: actions/checkout@v5 | 71 | uses: actions/checkout@v6 |
| 72 | - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate | 72 | - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate |
| 73 | uses: mxschmitt/action-tmate@v3 | 73 | uses: mxschmitt/action-tmate@v3 |
| 74 | if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} | 74 | if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} |
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1ac8aaf3..5a0b2943 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml | |||
| @@ -28,7 +28,7 @@ jobs: | |||
| 28 | prepare: .github/prepare_debian.sh | 28 | prepare: .github/prepare_debian.sh |
| 29 | steps: | 29 | steps: |
| 30 | - name: Git clone repository | 30 | - name: Git clone repository |
| 31 | uses: actions/checkout@v5 | 31 | uses: actions/checkout@v6 |
| 32 | - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate | 32 | - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate |
| 33 | uses: mxschmitt/action-tmate@v3 | 33 | uses: mxschmitt/action-tmate@v3 |
| 34 | if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} | 34 | if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} |
| @@ -69,7 +69,7 @@ jobs: | |||
| 69 | # - {"distro": "oraclelinux:9", "build": ".github/mock.sh"} | 69 | # - {"distro": "oraclelinux:9", "build": ".github/mock.sh"} |
| 70 | steps: | 70 | steps: |
| 71 | - name: Git clone repository | 71 | - name: Git clone repository |
| 72 | uses: actions/checkout@v5 | 72 | uses: actions/checkout@v6 |
| 73 | - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate | 73 | - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate |
| 74 | uses: mxschmitt/action-tmate@v3 | 74 | uses: mxschmitt/action-tmate@v3 |
| 75 | if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} | 75 | if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} |
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c index 35b83297..42c81793 100644 --- a/lib/utils_cmd.c +++ b/lib/utils_cmd.c | |||
| @@ -56,6 +56,7 @@ static pid_t *_cmd_pids = NULL; | |||
| 56 | #include "./maxfd.h" | 56 | #include "./maxfd.h" |
| 57 | 57 | ||
| 58 | #include <fcntl.h> | 58 | #include <fcntl.h> |
| 59 | #include <stddef.h> | ||
| 59 | 60 | ||
| 60 | #ifdef HAVE_SYS_WAIT_H | 61 | #ifdef HAVE_SYS_WAIT_H |
| 61 | # include <sys/wait.h> | 62 | # include <sys/wait.h> |
| @@ -79,7 +80,8 @@ static pid_t *_cmd_pids = NULL; | |||
| 79 | static int _cmd_open(char *const *argv, int *pfd, int *pfderr) | 80 | static int _cmd_open(char *const *argv, int *pfd, int *pfderr) |
| 80 | __attribute__((__nonnull__(1, 2, 3))); | 81 | __attribute__((__nonnull__(1, 2, 3))); |
| 81 | 82 | ||
| 82 | static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) __attribute__((__nonnull__(2))); | 83 | static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) |
| 84 | __attribute__((__nonnull__(2))); | ||
| 83 | 85 | ||
| 84 | static int _cmd_close(int fileDescriptor); | 86 | static int _cmd_close(int fileDescriptor); |
| 85 | 87 | ||
| @@ -102,14 +104,85 @@ void cmd_init(void) { | |||
| 102 | } | 104 | } |
| 103 | } | 105 | } |
| 104 | 106 | ||
| 107 | typedef struct { | ||
| 108 | int stdout_pipe_fd[2]; | ||
| 109 | int stderr_pipe_fd[2]; | ||
| 110 | int file_descriptor; | ||
| 111 | int error_code; | ||
| 112 | } int_cmd_open_result; | ||
| 113 | static int_cmd_open_result _cmd_open2(char *const *argv) { | ||
| 114 | #ifdef RLIMIT_CORE | ||
| 115 | struct rlimit limit; | ||
| 116 | #endif | ||
| 117 | |||
| 118 | if (!_cmd_pids) { | ||
| 119 | CMD_INIT; | ||
| 120 | } | ||
| 121 | |||
| 122 | setenv("LC_ALL", "C", 1); | ||
| 123 | |||
| 124 | int_cmd_open_result result = { | ||
| 125 | .error_code = 0, | ||
| 126 | .stdout_pipe_fd = {0, 0}, | ||
| 127 | .stderr_pipe_fd = {0, 0}, | ||
| 128 | }; | ||
| 129 | pid_t pid; | ||
| 130 | if (pipe(result.stdout_pipe_fd) < 0 || pipe(result.stderr_pipe_fd) < 0 || (pid = fork()) < 0) { | ||
| 131 | result.error_code = -1; | ||
| 132 | return result; /* errno set by the failing function */ | ||
| 133 | } | ||
| 134 | |||
| 135 | /* child runs exceve() and _exit. */ | ||
| 136 | if (pid == 0) { | ||
| 137 | #ifdef RLIMIT_CORE | ||
| 138 | /* the program we execve shouldn't leave core files */ | ||
| 139 | getrlimit(RLIMIT_CORE, &limit); | ||
| 140 | limit.rlim_cur = 0; | ||
| 141 | setrlimit(RLIMIT_CORE, &limit); | ||
| 142 | #endif | ||
| 143 | close(result.stdout_pipe_fd[0]); | ||
| 144 | if (result.stdout_pipe_fd[1] != STDOUT_FILENO) { | ||
| 145 | dup2(result.stdout_pipe_fd[1], STDOUT_FILENO); | ||
| 146 | close(result.stdout_pipe_fd[1]); | ||
| 147 | } | ||
| 148 | close(result.stderr_pipe_fd[0]); | ||
| 149 | if (result.stderr_pipe_fd[1] != STDERR_FILENO) { | ||
| 150 | dup2(result.stderr_pipe_fd[1], STDERR_FILENO); | ||
| 151 | close(result.stderr_pipe_fd[1]); | ||
| 152 | } | ||
| 153 | |||
| 154 | /* close all descriptors in _cmd_pids[] | ||
| 155 | * This is executed in a separate address space (pure child), | ||
| 156 | * so we don't have to worry about async safety */ | ||
| 157 | long maxfd = mp_open_max(); | ||
| 158 | for (int i = 0; i < maxfd; i++) { | ||
| 159 | if (_cmd_pids[i] > 0) { | ||
| 160 | close(i); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | execve(argv[0], argv, environ); | ||
| 165 | _exit(STATE_UNKNOWN); | ||
| 166 | } | ||
| 167 | |||
| 168 | /* parent picks up execution here */ | ||
| 169 | /* close children descriptors in our address space */ | ||
| 170 | close(result.stdout_pipe_fd[1]); | ||
| 171 | close(result.stderr_pipe_fd[1]); | ||
| 172 | |||
| 173 | /* tag our file's entry in the pid-list and return it */ | ||
| 174 | _cmd_pids[result.stdout_pipe_fd[0]] = pid; | ||
| 175 | |||
| 176 | result.file_descriptor = result.stdout_pipe_fd[0]; | ||
| 177 | return result; | ||
| 178 | } | ||
| 179 | |||
| 105 | /* Start running a command, array style */ | 180 | /* Start running a command, array style */ |
| 106 | static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { | 181 | static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { |
| 107 | #ifdef RLIMIT_CORE | 182 | #ifdef RLIMIT_CORE |
| 108 | struct rlimit limit; | 183 | struct rlimit limit; |
| 109 | #endif | 184 | #endif |
| 110 | 185 | ||
| 111 | int i = 0; | ||
| 112 | |||
| 113 | if (!_cmd_pids) { | 186 | if (!_cmd_pids) { |
| 114 | CMD_INIT; | 187 | CMD_INIT; |
| 115 | } | 188 | } |
| @@ -144,7 +217,7 @@ static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { | |||
| 144 | * This is executed in a separate address space (pure child), | 217 | * This is executed in a separate address space (pure child), |
| 145 | * so we don't have to worry about async safety */ | 218 | * so we don't have to worry about async safety */ |
| 146 | long maxfd = mp_open_max(); | 219 | long maxfd = mp_open_max(); |
| 147 | for (i = 0; i < maxfd; i++) { | 220 | for (int i = 0; i < maxfd; i++) { |
| 148 | if (_cmd_pids[i] > 0) { | 221 | if (_cmd_pids[i] > 0) { |
| 149 | close(i); | 222 | close(i); |
| 150 | } | 223 | } |
| @@ -192,6 +265,87 @@ static int _cmd_close(int fileDescriptor) { | |||
| 192 | return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; | 265 | return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; |
| 193 | } | 266 | } |
| 194 | 267 | ||
| 268 | typedef struct { | ||
| 269 | int error_code; | ||
| 270 | output output_container; | ||
| 271 | } int_cmd_fetch_output2; | ||
| 272 | static int_cmd_fetch_output2 _cmd_fetch_output2(int fileDescriptor, int flags) { | ||
| 273 | char tmpbuf[4096]; | ||
| 274 | |||
| 275 | int_cmd_fetch_output2 result = { | ||
| 276 | .error_code = 0, | ||
| 277 | .output_container = | ||
| 278 | { | ||
| 279 | .buf = NULL, | ||
| 280 | .buflen = 0, | ||
| 281 | .line = NULL, | ||
| 282 | .lines = 0, | ||
| 283 | }, | ||
| 284 | }; | ||
| 285 | ssize_t ret; | ||
| 286 | while ((ret = read(fileDescriptor, tmpbuf, sizeof(tmpbuf))) > 0) { | ||
| 287 | size_t len = (size_t)ret; | ||
| 288 | result.output_container.buf = | ||
| 289 | realloc(result.output_container.buf, result.output_container.buflen + len + 1); | ||
| 290 | memcpy(result.output_container.buf + result.output_container.buflen, tmpbuf, len); | ||
| 291 | result.output_container.buflen += len; | ||
| 292 | } | ||
| 293 | |||
| 294 | if (ret < 0) { | ||
| 295 | printf("read() returned %zd: %s\n", ret, strerror(errno)); | ||
| 296 | result.error_code = -1; | ||
| 297 | return result; | ||
| 298 | } | ||
| 299 | |||
| 300 | /* some plugins may want to keep output unbroken, and some commands | ||
| 301 | * will yield no output, so return here for those */ | ||
| 302 | if (flags & CMD_NO_ARRAYS || !result.output_container.buf || !result.output_container.buflen) { | ||
| 303 | return result; | ||
| 304 | } | ||
| 305 | |||
| 306 | /* and some may want both */ | ||
| 307 | char *buf = NULL; | ||
| 308 | if (flags & CMD_NO_ASSOC) { | ||
| 309 | buf = malloc(result.output_container.buflen); | ||
| 310 | memcpy(buf, result.output_container.buf, result.output_container.buflen); | ||
| 311 | } else { | ||
| 312 | buf = result.output_container.buf; | ||
| 313 | } | ||
| 314 | |||
| 315 | result.output_container.line = NULL; | ||
| 316 | size_t ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ | ||
| 317 | size_t rsf = 6; | ||
| 318 | size_t lineno = 0; | ||
| 319 | for (size_t i = 0; i < result.output_container.buflen;) { | ||
| 320 | /* make sure we have enough memory */ | ||
| 321 | if (lineno >= ary_size) { | ||
| 322 | /* ary_size must never be zero */ | ||
| 323 | do { | ||
| 324 | ary_size = result.output_container.buflen >> --rsf; | ||
| 325 | } while (!ary_size); | ||
| 326 | |||
| 327 | result.output_container.line = | ||
| 328 | realloc(result.output_container.line, ary_size * sizeof(char *)); | ||
| 329 | } | ||
| 330 | |||
| 331 | /* set the pointer to the string */ | ||
| 332 | result.output_container.line[lineno] = &buf[i]; | ||
| 333 | |||
| 334 | /* hop to next newline or end of buffer */ | ||
| 335 | while (buf[i] != '\n' && i < result.output_container.buflen) { | ||
| 336 | i++; | ||
| 337 | } | ||
| 338 | buf[i] = '\0'; | ||
| 339 | |||
| 340 | lineno++; | ||
| 341 | i++; | ||
| 342 | } | ||
| 343 | |||
| 344 | result.output_container.lines = lineno; | ||
| 345 | |||
| 346 | return result; | ||
| 347 | } | ||
| 348 | |||
| 195 | static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) { | 349 | static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) { |
| 196 | char tmpbuf[4096]; | 350 | char tmpbuf[4096]; |
| 197 | cmd_output->buf = NULL; | 351 | cmd_output->buf = NULL; |
| @@ -225,7 +379,6 @@ static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) | |||
| 225 | } | 379 | } |
| 226 | 380 | ||
| 227 | cmd_output->line = NULL; | 381 | cmd_output->line = NULL; |
| 228 | cmd_output->lens = NULL; | ||
| 229 | size_t i = 0; | 382 | size_t i = 0; |
| 230 | size_t ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ | 383 | size_t ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ |
| 231 | size_t rsf = 6; | 384 | size_t rsf = 6; |
| @@ -239,7 +392,6 @@ static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) | |||
| 239 | } while (!ary_size); | 392 | } while (!ary_size); |
| 240 | 393 | ||
| 241 | cmd_output->line = realloc(cmd_output->line, ary_size * sizeof(char *)); | 394 | cmd_output->line = realloc(cmd_output->line, ary_size * sizeof(char *)); |
| 242 | cmd_output->lens = realloc(cmd_output->lens, ary_size * sizeof(size_t)); | ||
| 243 | } | 395 | } |
| 244 | 396 | ||
| 245 | /* set the pointer to the string */ | 397 | /* set the pointer to the string */ |
| @@ -251,9 +403,6 @@ static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) | |||
| 251 | } | 403 | } |
| 252 | buf[i] = '\0'; | 404 | buf[i] = '\0'; |
| 253 | 405 | ||
| 254 | /* calculate the string length using pointer difference */ | ||
| 255 | cmd_output->lens[lineno] = (size_t)&buf[i] - (size_t)cmd_output->line[lineno]; | ||
| 256 | |||
| 257 | lineno++; | 406 | lineno++; |
| 258 | i++; | 407 | i++; |
| 259 | } | 408 | } |
| @@ -336,6 +485,139 @@ int cmd_run(const char *cmdstring, output *out, output *err, int flags) { | |||
| 336 | return cmd_run_array(argv, out, err, flags); | 485 | return cmd_run_array(argv, out, err, flags); |
| 337 | } | 486 | } |
| 338 | 487 | ||
| 488 | cmd_run_result cmd_run2(const char *cmd_string, int flags) { | ||
| 489 | cmd_run_result result = { | ||
| 490 | .cmd_error_code = 0, | ||
| 491 | .error_code = 0, | ||
| 492 | .stderr = | ||
| 493 | { | ||
| 494 | .buf = NULL, | ||
| 495 | .buflen = 0, | ||
| 496 | .line = NULL, | ||
| 497 | .lines = 0, | ||
| 498 | }, | ||
| 499 | .stdout = | ||
| 500 | { | ||
| 501 | .buf = NULL, | ||
| 502 | .buflen = 0, | ||
| 503 | .line = NULL, | ||
| 504 | .lines = 0, | ||
| 505 | }, | ||
| 506 | }; | ||
| 507 | |||
| 508 | if (cmd_string == NULL) { | ||
| 509 | result.error_code = -1; | ||
| 510 | return result; | ||
| 511 | } | ||
| 512 | |||
| 513 | /* make copy of command string so strtok() doesn't silently modify it */ | ||
| 514 | /* (the calling program may want to access it later) */ | ||
| 515 | char *cmd = strdup(cmd_string); | ||
| 516 | if (cmd == NULL) { | ||
| 517 | result.error_code = -1; | ||
| 518 | return result; | ||
| 519 | } | ||
| 520 | |||
| 521 | /* This is not a shell, so we don't handle "???" */ | ||
| 522 | if (strstr(cmd, "\"")) { | ||
| 523 | result.error_code = -1; | ||
| 524 | return result; | ||
| 525 | } | ||
| 526 | |||
| 527 | /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ | ||
| 528 | if (strstr(cmd, " ' ") || strstr(cmd, "'''")) { | ||
| 529 | result.error_code = -1; | ||
| 530 | return result; | ||
| 531 | } | ||
| 532 | |||
| 533 | /* each arg must be whitespace-separated, so args can be a maximum | ||
| 534 | * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ | ||
| 535 | size_t cmdlen = strlen(cmd_string); | ||
| 536 | size_t argc = (cmdlen >> 1) + 2; | ||
| 537 | char **argv = calloc(argc, sizeof(char *)); | ||
| 538 | |||
| 539 | if (argv == NULL) { | ||
| 540 | printf("%s\n", _("Could not malloc argv array in popen()")); | ||
| 541 | result.error_code = -1; | ||
| 542 | return result; | ||
| 543 | } | ||
| 544 | |||
| 545 | /* get command arguments (stupidly, but fairly quickly) */ | ||
| 546 | for (int i = 0; cmd; i++) { | ||
| 547 | char *str = cmd; | ||
| 548 | str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ | ||
| 549 | |||
| 550 | if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */ | ||
| 551 | str++; | ||
| 552 | if (!strstr(str, "'")) { | ||
| 553 | result.error_code = -1; | ||
| 554 | return result; /* balanced? */ | ||
| 555 | } | ||
| 556 | |||
| 557 | cmd = 1 + strstr(str, "'"); | ||
| 558 | str[strcspn(str, "'")] = 0; | ||
| 559 | } else { | ||
| 560 | if (strpbrk(str, " \t\r\n")) { | ||
| 561 | cmd = 1 + strpbrk(str, " \t\r\n"); | ||
| 562 | str[strcspn(str, " \t\r\n")] = 0; | ||
| 563 | } else { | ||
| 564 | cmd = NULL; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | |||
| 568 | if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) { | ||
| 569 | cmd = NULL; | ||
| 570 | } | ||
| 571 | |||
| 572 | argv[i++] = str; | ||
| 573 | } | ||
| 574 | |||
| 575 | result = cmd_run_array2(argv, flags); | ||
| 576 | |||
| 577 | return result; | ||
| 578 | } | ||
| 579 | |||
| 580 | cmd_run_result cmd_run_array2(char *const *cmd, int flags) { | ||
| 581 | cmd_run_result result = { | ||
| 582 | .cmd_error_code = 0, | ||
| 583 | .error_code = 0, | ||
| 584 | .stderr = | ||
| 585 | { | ||
| 586 | .buf = NULL, | ||
| 587 | .buflen = 0, | ||
| 588 | .line = NULL, | ||
| 589 | .lines = 0, | ||
| 590 | }, | ||
| 591 | .stdout = | ||
| 592 | { | ||
| 593 | .buf = NULL, | ||
| 594 | .buflen = 0, | ||
| 595 | .line = NULL, | ||
| 596 | .lines = 0, | ||
| 597 | }, | ||
| 598 | }; | ||
| 599 | |||
| 600 | int_cmd_open_result cmd_open_result = _cmd_open2(cmd); | ||
| 601 | if (cmd_open_result.error_code != 0) { | ||
| 602 | // result.error_code = -1; | ||
| 603 | // return result; | ||
| 604 | // TODO properly handle this without dying | ||
| 605 | die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd[0]); | ||
| 606 | } | ||
| 607 | |||
| 608 | int file_descriptor = cmd_open_result.file_descriptor; | ||
| 609 | int pfd_out[2] = {cmd_open_result.stdout_pipe_fd[0], cmd_open_result.stdout_pipe_fd[1]}; | ||
| 610 | int pfd_err[2] = {cmd_open_result.stderr_pipe_fd[0], cmd_open_result.stderr_pipe_fd[1]}; | ||
| 611 | |||
| 612 | int_cmd_fetch_output2 tmp_stdout = _cmd_fetch_output2(pfd_out[0], flags); | ||
| 613 | result.stdout = tmp_stdout.output_container; | ||
| 614 | int_cmd_fetch_output2 tmp_stderr = _cmd_fetch_output2(pfd_err[0], flags); | ||
| 615 | result.stderr = tmp_stderr.output_container; | ||
| 616 | |||
| 617 | result.cmd_error_code = _cmd_close(file_descriptor); | ||
| 618 | return result; | ||
| 619 | } | ||
| 620 | |||
| 339 | int cmd_run_array(char *const *argv, output *out, output *err, int flags) { | 621 | int cmd_run_array(char *const *argv, output *out, output *err, int flags) { |
| 340 | /* initialize the structs */ | 622 | /* initialize the structs */ |
| 341 | if (out) { | 623 | if (out) { |
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h index 3672cdc9..d3a8f14f 100644 --- a/lib/utils_cmd.h +++ b/lib/utils_cmd.h | |||
| @@ -13,7 +13,6 @@ typedef struct { | |||
| 13 | char *buf; /* output buffer */ | 13 | char *buf; /* output buffer */ |
| 14 | size_t buflen; /* output buffer content length */ | 14 | size_t buflen; /* output buffer content length */ |
| 15 | char **line; /* array of lines (points to buf) */ | 15 | char **line; /* array of lines (points to buf) */ |
| 16 | size_t *lens; /* string lengths */ | ||
| 17 | size_t lines; /* lines of output */ | 16 | size_t lines; /* lines of output */ |
| 18 | } output; | 17 | } output; |
| 19 | 18 | ||
| @@ -22,6 +21,15 @@ int cmd_run(const char *, output *, output *, int); | |||
| 22 | int cmd_run_array(char *const *, output *, output *, int); | 21 | int cmd_run_array(char *const *, output *, output *, int); |
| 23 | int cmd_file_read(const char *, output *, int); | 22 | int cmd_file_read(const char *, output *, int); |
| 24 | 23 | ||
| 24 | typedef struct { | ||
| 25 | int error_code; | ||
| 26 | int cmd_error_code; | ||
| 27 | output stdout; | ||
| 28 | output stderr; | ||
| 29 | } cmd_run_result; | ||
| 30 | cmd_run_result cmd_run2(const char *cmd, int flags); | ||
| 31 | cmd_run_result cmd_run_array2(char * const *cmd, int flags); | ||
| 32 | |||
| 25 | /* only multi-threaded plugins need to bother with this */ | 33 | /* only multi-threaded plugins need to bother with this */ |
| 26 | void cmd_init(void); | 34 | void cmd_init(void); |
| 27 | #define CMD_INIT cmd_init() | 35 | #define CMD_INIT cmd_init() |
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c index a43c0d34..df8907d9 100644 --- a/plugins/check_by_ssh.c +++ b/plugins/check_by_ssh.c | |||
| @@ -26,16 +26,17 @@ | |||
| 26 | * | 26 | * |
| 27 | *****************************************************************************/ | 27 | *****************************************************************************/ |
| 28 | 28 | ||
| 29 | const char *progname = "check_by_ssh"; | ||
| 30 | const char *copyright = "2000-2024"; | ||
| 31 | const char *email = "devel@monitoring-plugins.org"; | ||
| 32 | |||
| 33 | #include "common.h" | 29 | #include "common.h" |
| 30 | #include "output.h" | ||
| 34 | #include "utils.h" | 31 | #include "utils.h" |
| 35 | #include "utils_cmd.h" | 32 | #include "utils_cmd.h" |
| 36 | #include "check_by_ssh.d/config.h" | 33 | #include "check_by_ssh.d/config.h" |
| 37 | #include "states.h" | 34 | #include "states.h" |
| 38 | 35 | ||
| 36 | const char *progname = "check_by_ssh"; | ||
| 37 | const char *copyright = "2000-2024"; | ||
| 38 | const char *email = "devel@monitoring-plugins.org"; | ||
| 39 | |||
| 39 | #ifndef NP_MAXARGS | 40 | #ifndef NP_MAXARGS |
| 40 | # define NP_MAXARGS 1024 | 41 | # define NP_MAXARGS 1024 |
| 41 | #endif | 42 | #endif |
| @@ -71,6 +72,10 @@ int main(int argc, char **argv) { | |||
| 71 | 72 | ||
| 72 | const check_by_ssh_config config = tmp_config.config; | 73 | const check_by_ssh_config config = tmp_config.config; |
| 73 | 74 | ||
| 75 | if (config.output_format_is_set) { | ||
| 76 | mp_set_format(config.output_format); | ||
| 77 | } | ||
| 78 | |||
| 74 | /* Set signal handling and alarm timeout */ | 79 | /* Set signal handling and alarm timeout */ |
| 75 | if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { | 80 | if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { |
| 76 | usage_va(_("Cannot catch SIGALRM")); | 81 | usage_va(_("Cannot catch SIGALRM")); |
| @@ -85,62 +90,99 @@ int main(int argc, char **argv) { | |||
| 85 | } | 90 | } |
| 86 | } | 91 | } |
| 87 | 92 | ||
| 88 | output chld_out; | 93 | cmd_run_result child_result = cmd_run_array2(config.cmd.commargv, 0); |
| 89 | output chld_err; | 94 | mp_check overall = mp_check_init(); |
| 90 | mp_state_enum result = cmd_run_array(config.cmd.commargv, &chld_out, &chld_err, 0); | ||
| 91 | 95 | ||
| 92 | /* SSH returns 255 if connection attempt fails; include the first line of error output */ | 96 | /* SSH returns 255 if connection attempt fails; include the first line of error output */ |
| 93 | if (result == 255 && config.unknown_timeout) { | 97 | // we can sadly not detect other SSH errors |
| 94 | printf(_("SSH connection failed: %s\n"), | 98 | if (child_result.cmd_error_code == 255 && config.unknown_timeout) { |
| 95 | chld_err.lines > 0 ? chld_err.line[0] : "(no error output)"); | 99 | mp_subcheck sc_ssh_execution = mp_subcheck_init(); |
| 96 | return STATE_UNKNOWN; | 100 | xasprintf(&sc_ssh_execution.output, "SSH connection failed: %s", |
| 101 | child_result.stderr.lines > 0 ? child_result.stderr.line[0] | ||
| 102 | : "(no error output)"); | ||
| 103 | |||
| 104 | sc_ssh_execution = mp_set_subcheck_state(sc_ssh_execution, STATE_UNKNOWN); | ||
| 105 | mp_add_subcheck_to_check(&overall, sc_ssh_execution); | ||
| 106 | mp_exit(overall); | ||
| 97 | } | 107 | } |
| 98 | 108 | ||
| 99 | if (verbose) { | 109 | if (verbose) { |
| 100 | for (size_t i = 0; i < chld_out.lines; i++) { | 110 | for (size_t i = 0; i < child_result.stdout.lines; i++) { |
| 101 | printf("stdout: %s\n", chld_out.line[i]); | 111 | printf("stdout: %s\n", child_result.stdout.line[i]); |
| 102 | } | 112 | } |
| 103 | for (size_t i = 0; i < chld_err.lines; i++) { | 113 | for (size_t i = 0; i < child_result.stderr.lines; i++) { |
| 104 | printf("stderr: %s\n", chld_err.line[i]); | 114 | printf("stderr: %s\n", child_result.stderr.line[i]); |
| 105 | } | 115 | } |
| 106 | } | 116 | } |
| 107 | 117 | ||
| 108 | size_t skip_stdout = 0; | 118 | size_t skip_stdout = 0; |
| 109 | if (config.skip_stdout == -1) { /* --skip-stdout specified without argument */ | 119 | if (config.skip_stdout) { /* --skip-stdout specified without argument */ |
| 110 | skip_stdout = chld_out.lines; | 120 | skip_stdout = child_result.stdout.lines; |
| 111 | } else { | 121 | } else { |
| 112 | skip_stdout = config.skip_stdout; | 122 | skip_stdout = config.stdout_lines_to_ignore; |
| 113 | } | 123 | } |
| 114 | 124 | ||
| 115 | size_t skip_stderr = 0; | 125 | size_t skip_stderr = 0; |
| 116 | if (config.skip_stderr == -1) { /* --skip-stderr specified without argument */ | 126 | if (config.skip_stderr) { /* --skip-stderr specified without argument */ |
| 117 | skip_stderr = chld_err.lines; | 127 | skip_stderr = child_result.stderr.lines; |
| 118 | } else { | 128 | } else { |
| 119 | skip_stderr = config.skip_stderr; | 129 | skip_stderr = config.sterr_lines_to_ignore; |
| 120 | } | 130 | } |
| 121 | 131 | ||
| 122 | /* Allow UNKNOWN or WARNING state for (non-skipped) output found on stderr */ | 132 | /* Allow UNKNOWN or WARNING state for (non-skipped) output found on stderr */ |
| 123 | if (chld_err.lines > (size_t)skip_stderr && (config.unknown_on_stderr || config.warn_on_stderr)) { | 133 | if (child_result.stderr.lines > skip_stderr && |
| 124 | printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]); | 134 | (config.unknown_on_stderr || config.warn_on_stderr)) { |
| 135 | mp_subcheck sc_stderr = mp_subcheck_init(); | ||
| 136 | xasprintf(&sc_stderr.output, "remote command execution failed: %s", | ||
| 137 | child_result.stderr.line[skip_stderr]); | ||
| 138 | |||
| 125 | if (config.unknown_on_stderr) { | 139 | if (config.unknown_on_stderr) { |
| 126 | return max_state_alt(result, STATE_UNKNOWN); | 140 | sc_stderr = mp_set_subcheck_state(sc_stderr, STATE_UNKNOWN); |
| 127 | } else if (config.warn_on_stderr) { | 141 | } |
| 128 | return max_state_alt(result, STATE_WARNING); | 142 | |
| 143 | if (config.warn_on_stderr) { | ||
| 144 | sc_stderr = mp_set_subcheck_state(sc_stderr, STATE_WARNING); | ||
| 129 | } | 145 | } |
| 146 | |||
| 147 | mp_add_subcheck_to_check(&overall, sc_stderr); | ||
| 148 | // TODO still exit here? | ||
| 130 | } | 149 | } |
| 131 | 150 | ||
| 132 | /* this is simple if we're not supposed to be passive. | 151 | /* this is simple if we're not supposed to be passive. |
| 133 | * Wrap up quickly and keep the tricks below */ | 152 | * Wrap up quickly and keep the tricks below */ |
| 134 | if (!config.passive) { | 153 | if (!config.passive) { |
| 135 | if (chld_out.lines > (size_t)skip_stdout) { | 154 | mp_subcheck sc_active_check = mp_subcheck_init(); |
| 136 | for (size_t i = skip_stdout; i < chld_out.lines; i++) { | 155 | xasprintf(&sc_active_check.output, "command stdout:"); |
| 137 | puts(chld_out.line[i]); | 156 | |
| 157 | if (child_result.stdout.lines > skip_stdout) { | ||
| 158 | for (size_t i = skip_stdout; i < child_result.stdout.lines; i++) { | ||
| 159 | xasprintf(&sc_active_check.output, "%s\n%s", sc_active_check.output, | ||
| 160 | child_result.stdout.line[i]); | ||
| 138 | } | 161 | } |
| 139 | } else { | 162 | } else { |
| 140 | printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), | 163 | xasprintf(&sc_active_check.output, "remote command '%s' returned status %d", |
| 141 | state_text(result), config.remotecmd, result); | 164 | config.remotecmd, child_result.cmd_error_code); |
| 165 | } | ||
| 166 | |||
| 167 | /* return error status from remote command */ | ||
| 168 | |||
| 169 | switch (child_result.cmd_error_code) { | ||
| 170 | case 0: | ||
| 171 | sc_active_check = mp_set_subcheck_state(sc_active_check, STATE_OK); | ||
| 172 | break; | ||
| 173 | case 1: | ||
| 174 | sc_active_check = mp_set_subcheck_state(sc_active_check, STATE_WARNING); | ||
| 175 | break; | ||
| 176 | case 2: | ||
| 177 | sc_active_check = mp_set_subcheck_state(sc_active_check, STATE_CRITICAL); | ||
| 178 | break; | ||
| 179 | default: | ||
| 180 | sc_active_check = mp_set_subcheck_state(sc_active_check, STATE_UNKNOWN); | ||
| 181 | break; | ||
| 142 | } | 182 | } |
| 143 | return result; /* return error status from remote command */ | 183 | |
| 184 | mp_add_subcheck_to_check(&overall, sc_active_check); | ||
| 185 | mp_exit(overall); | ||
| 144 | } | 186 | } |
| 145 | 187 | ||
| 146 | /* | 188 | /* |
| @@ -148,36 +190,57 @@ int main(int argc, char **argv) { | |||
| 148 | */ | 190 | */ |
| 149 | 191 | ||
| 150 | /* process output */ | 192 | /* process output */ |
| 151 | FILE *file_pointer = NULL; | 193 | mp_subcheck sc_passive_file = mp_subcheck_init(); |
| 152 | if (!(file_pointer = fopen(config.outputfile, "a"))) { | 194 | FILE *output_file = NULL; |
| 153 | printf(_("SSH WARNING: could not open %s\n"), config.outputfile); | 195 | if (!(output_file = fopen(config.outputfile, "a"))) { |
| 154 | exit(STATE_UNKNOWN); | 196 | xasprintf(&sc_passive_file.output, "could not open %s", config.outputfile); |
| 197 | sc_passive_file = mp_set_subcheck_state(sc_passive_file, STATE_UNKNOWN); | ||
| 198 | |||
| 199 | mp_add_subcheck_to_check(&overall, sc_passive_file); | ||
| 200 | mp_exit(overall); | ||
| 155 | } | 201 | } |
| 156 | 202 | ||
| 203 | xasprintf(&sc_passive_file.output, "opened output file %s", config.outputfile); | ||
| 204 | sc_passive_file = mp_set_subcheck_state(sc_passive_file, STATE_OK); | ||
| 205 | mp_add_subcheck_to_check(&overall, sc_passive_file); | ||
| 206 | |||
| 157 | time_t local_time = time(NULL); | 207 | time_t local_time = time(NULL); |
| 158 | unsigned int commands = 0; | 208 | unsigned int commands = 0; |
| 159 | char *status_text; | 209 | char *status_text; |
| 160 | int cresult; | 210 | int cresult; |
| 161 | for (size_t i = skip_stdout; i < chld_out.lines; i++) { | 211 | mp_subcheck sc_parse_passive = mp_subcheck_init(); |
| 162 | status_text = chld_out.line[i++]; | 212 | for (size_t i = skip_stdout; i < child_result.stdout.lines; i++) { |
| 163 | if (i == chld_out.lines || strstr(chld_out.line[i], "STATUS CODE: ") == NULL) { | 213 | status_text = child_result.stdout.line[i++]; |
| 164 | die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname); | 214 | if (i == child_result.stdout.lines || |
| 215 | strstr(child_result.stdout.line[i], "STATUS CODE: ") == NULL) { | ||
| 216 | |||
| 217 | sc_parse_passive = mp_set_subcheck_state(sc_parse_passive, STATE_UNKNOWN); | ||
| 218 | xasprintf(&sc_parse_passive.output, "failed to parse output"); | ||
| 219 | mp_add_subcheck_to_check(&overall, sc_parse_passive); | ||
| 220 | mp_exit(overall); | ||
| 165 | } | 221 | } |
| 166 | 222 | ||
| 167 | if (config.service[commands] && status_text && | 223 | if (config.service[commands] && status_text && |
| 168 | sscanf(chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) { | 224 | sscanf(child_result.stdout.line[i], "STATUS CODE: %d", &cresult) == 1) { |
| 169 | fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", | 225 | fprintf(output_file, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, |
| 170 | (int)local_time, config.host_shortname, config.service[commands++], cresult, | 226 | config.host_shortname, config.service[commands++], cresult, status_text); |
| 171 | status_text); | ||
| 172 | } | 227 | } |
| 173 | } | 228 | } |
| 174 | 229 | ||
| 230 | sc_parse_passive = mp_set_subcheck_state(sc_parse_passive, STATE_OK); | ||
| 231 | xasprintf(&sc_parse_passive.output, "parsed and wrote output"); | ||
| 232 | mp_add_subcheck_to_check(&overall, sc_parse_passive); | ||
| 233 | |||
| 175 | /* Multiple commands and passive checking should always return OK */ | 234 | /* Multiple commands and passive checking should always return OK */ |
| 176 | exit(result); | 235 | mp_exit(overall); |
| 177 | } | 236 | } |
| 178 | 237 | ||
| 179 | /* process command-line arguments */ | 238 | /* process command-line arguments */ |
| 180 | check_by_ssh_config_wrapper process_arguments(int argc, char **argv) { | 239 | check_by_ssh_config_wrapper process_arguments(int argc, char **argv) { |
| 240 | enum { | ||
| 241 | output_format_index = CHAR_MAX + 1, | ||
| 242 | }; | ||
| 243 | |||
| 181 | static struct option longopts[] = { | 244 | static struct option longopts[] = { |
| 182 | {"version", no_argument, 0, 'V'}, | 245 | {"version", no_argument, 0, 'V'}, |
| 183 | {"help", no_argument, 0, 'h'}, | 246 | {"help", no_argument, 0, 'h'}, |
| @@ -207,6 +270,7 @@ check_by_ssh_config_wrapper process_arguments(int argc, char **argv) { | |||
| 207 | {"ssh-option", required_argument, 0, 'o'}, | 270 | {"ssh-option", required_argument, 0, 'o'}, |
| 208 | {"quiet", no_argument, 0, 'q'}, | 271 | {"quiet", no_argument, 0, 'q'}, |
| 209 | {"configfile", optional_argument, 0, 'F'}, | 272 | {"configfile", optional_argument, 0, 'F'}, |
| 273 | {"output-format", required_argument, 0, output_format_index}, | ||
| 210 | {0, 0, 0, 0}}; | 274 | {0, 0, 0, 0}}; |
| 211 | 275 | ||
| 212 | check_by_ssh_config_wrapper result = { | 276 | check_by_ssh_config_wrapper result = { |
| @@ -327,20 +391,27 @@ check_by_ssh_config_wrapper process_arguments(int argc, char **argv) { | |||
| 327 | break; | 391 | break; |
| 328 | case 'S': /* skip n (or all) lines on stdout */ | 392 | case 'S': /* skip n (or all) lines on stdout */ |
| 329 | if (optarg == NULL) { | 393 | if (optarg == NULL) { |
| 330 | result.config.skip_stdout = -1; /* skip all output on stdout */ | 394 | result.config.skip_stdout = true; /* skip all output on stdout */ |
| 395 | |||
| 396 | if (verbose) { | ||
| 397 | printf("Setting the skip_stdout flag\n"); | ||
| 398 | } | ||
| 331 | } else if (!is_integer(optarg)) { | 399 | } else if (!is_integer(optarg)) { |
| 332 | usage_va(_("skip-stdout argument must be an integer")); | 400 | usage_va(_("skip-stdout argument must be an integer")); |
| 333 | } else { | 401 | } else { |
| 334 | result.config.skip_stdout = atoi(optarg); | 402 | result.config.stdout_lines_to_ignore = atoi(optarg); |
| 335 | } | 403 | } |
| 336 | break; | 404 | break; |
| 337 | case 'E': /* skip n (or all) lines on stderr */ | 405 | case 'E': /* skip n (or all) lines on stderr */ |
| 338 | if (optarg == NULL) { | 406 | if (optarg == NULL) { |
| 339 | result.config.skip_stderr = -1; /* skip all output on stderr */ | 407 | result.config.skip_stderr = true; /* skip all output on stderr */ |
| 408 | if (verbose) { | ||
| 409 | printf("Setting the skip_stderr flag\n"); | ||
| 410 | } | ||
| 340 | } else if (!is_integer(optarg)) { | 411 | } else if (!is_integer(optarg)) { |
| 341 | usage_va(_("skip-stderr argument must be an integer")); | 412 | usage_va(_("skip-stderr argument must be an integer")); |
| 342 | } else { | 413 | } else { |
| 343 | result.config.skip_stderr = atoi(optarg); | 414 | result.config.sterr_lines_to_ignore = atoi(optarg); |
| 344 | } | 415 | } |
| 345 | break; | 416 | break; |
| 346 | case 'e': /* exit with unknown if there is an output on stderr */ | 417 | case 'e': /* exit with unknown if there is an output on stderr */ |
| @@ -360,6 +431,18 @@ check_by_ssh_config_wrapper process_arguments(int argc, char **argv) { | |||
| 360 | result.config.cmd = comm_append(result.config.cmd, "-F"); | 431 | result.config.cmd = comm_append(result.config.cmd, "-F"); |
| 361 | result.config.cmd = comm_append(result.config.cmd, optarg); | 432 | result.config.cmd = comm_append(result.config.cmd, optarg); |
| 362 | break; | 433 | break; |
| 434 | case output_format_index: { | ||
| 435 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 436 | if (!parser.parsing_success) { | ||
| 437 | // TODO List all available formats here, maybe add anothoer usage function | ||
| 438 | printf("Invalid output format: %s\n", optarg); | ||
| 439 | exit(STATE_UNKNOWN); | ||
| 440 | } | ||
| 441 | |||
| 442 | result.config.output_format_is_set = true; | ||
| 443 | result.config.output_format = parser.output_format; | ||
| 444 | break; | ||
| 445 | } | ||
| 363 | default: /* help */ | 446 | default: /* help */ |
| 364 | usage5(); | 447 | usage5(); |
| 365 | } | 448 | } |
| @@ -502,6 +585,7 @@ void print_help(void) { | |||
| 502 | printf(" %s\n", "-U, --unknown-timeout"); | 585 | printf(" %s\n", "-U, --unknown-timeout"); |
| 503 | printf(" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL")); | 586 | printf(" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL")); |
| 504 | printf(UT_VERBOSE); | 587 | printf(UT_VERBOSE); |
| 588 | printf(UT_OUTPUT_FORMAT); | ||
| 505 | printf("\n"); | 589 | printf("\n"); |
| 506 | printf(" %s\n", _("The most common mode of use is to refer to a local identity file with")); | 590 | printf(" %s\n", _("The most common mode of use is to refer to a local identity file with")); |
| 507 | printf(" %s\n", _("the '-i' option. In this mode, the identity pair should have a null")); | 591 | printf(" %s\n", _("the '-i' option. In this mode, the identity pair should have a null")); |
| @@ -515,9 +599,8 @@ void print_help(void) { | |||
| 515 | printf(" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)")); | 599 | printf(" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)")); |
| 516 | printf("\n"); | 600 | printf("\n"); |
| 517 | printf("%s\n", _("Examples:")); | 601 | printf("%s\n", _("Examples:")); |
| 518 | printf( | 602 | printf(" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C " |
| 519 | " %s\n", | 603 | "uptime -O /tmp/foo"); |
| 520 | "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo"); | ||
| 521 | printf(" %s\n", "$ cat /tmp/foo"); | 604 | printf(" %s\n", "$ cat /tmp/foo"); |
| 522 | printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days"); | 605 | printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days"); |
| 523 | printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days"); | 606 | printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days"); |
diff --git a/plugins/check_by_ssh.d/config.h b/plugins/check_by_ssh.d/config.h index 0e4b56d4..b6a57964 100644 --- a/plugins/check_by_ssh.d/config.h +++ b/plugins/check_by_ssh.d/config.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 4 | #include <stddef.h> | 5 | #include <stddef.h> |
| 5 | 6 | ||
| 6 | typedef struct { | 7 | typedef struct { |
| @@ -23,10 +24,16 @@ typedef struct { | |||
| 23 | bool unknown_timeout; | 24 | bool unknown_timeout; |
| 24 | bool unknown_on_stderr; | 25 | bool unknown_on_stderr; |
| 25 | bool warn_on_stderr; | 26 | bool warn_on_stderr; |
| 26 | int skip_stdout; | 27 | bool skip_stdout; |
| 27 | int skip_stderr; | 28 | size_t stdout_lines_to_ignore; |
| 29 | bool skip_stderr; | ||
| 30 | size_t sterr_lines_to_ignore; | ||
| 31 | |||
| 28 | bool passive; | 32 | bool passive; |
| 29 | char *outputfile; | 33 | char *outputfile; |
| 34 | |||
| 35 | bool output_format_is_set; | ||
| 36 | mp_output_format output_format; | ||
| 30 | } check_by_ssh_config; | 37 | } check_by_ssh_config; |
| 31 | 38 | ||
| 32 | check_by_ssh_config check_by_ssh_config_init() { | 39 | check_by_ssh_config check_by_ssh_config_init() { |
| @@ -49,10 +56,16 @@ check_by_ssh_config check_by_ssh_config_init() { | |||
| 49 | .unknown_timeout = false, | 56 | .unknown_timeout = false, |
| 50 | .unknown_on_stderr = false, | 57 | .unknown_on_stderr = false, |
| 51 | .warn_on_stderr = false, | 58 | .warn_on_stderr = false, |
| 52 | .skip_stderr = 0, | 59 | |
| 53 | .skip_stdout = 0, | 60 | .skip_stderr = false, |
| 61 | .stdout_lines_to_ignore = 0, | ||
| 62 | .skip_stdout = false, | ||
| 63 | .sterr_lines_to_ignore = 0, | ||
| 64 | |||
| 54 | .passive = false, | 65 | .passive = false, |
| 55 | .outputfile = NULL, | 66 | .outputfile = NULL, |
| 67 | |||
| 68 | .output_format_is_set = false, | ||
| 56 | }; | 69 | }; |
| 57 | return tmp; | 70 | return tmp; |
| 58 | } | 71 | } |
diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c index c3c2ba55..d49d8f07 100644 --- a/plugins/check_curl.d/check_curl_helpers.c +++ b/plugins/check_curl.d/check_curl_helpers.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <netinet/in.h> | 4 | #include <netinet/in.h> |
| 5 | #include <netdb.h> | 5 | #include <netdb.h> |
| 6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
| 7 | #include <string.h> | ||
| 7 | #include "../utils.h" | 8 | #include "../utils.h" |
| 8 | #include "check_curl.d/config.h" | 9 | #include "check_curl.d/config.h" |
| 9 | #include "output.h" | 10 | #include "output.h" |
| @@ -816,7 +817,10 @@ int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) | |||
| 816 | buf = start; | 817 | buf = start; |
| 817 | } | 818 | } |
| 818 | 819 | ||
| 819 | char *first_line_end = strstr(buf, "\r\n"); | 820 | // Accept either LF or CRLF as end of line for the status line |
| 821 | // CRLF is the standard (RFC9112), but it is recommended to accept both | ||
| 822 | size_t length_of_first_line = strcspn(buf, "\r\n"); | ||
| 823 | const char *first_line_end = &buf[length_of_first_line]; | ||
| 820 | if (first_line_end == NULL) { | 824 | if (first_line_end == NULL) { |
| 821 | return -1; | 825 | return -1; |
| 822 | } | 826 | } |
| @@ -826,6 +830,7 @@ int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) | |||
| 826 | if (status_line->first_line == NULL) { | 830 | if (status_line->first_line == NULL) { |
| 827 | return -1; | 831 | return -1; |
| 828 | } | 832 | } |
| 833 | |||
| 829 | memcpy(status_line->first_line, buf, first_line_len); | 834 | memcpy(status_line->first_line, buf, first_line_len); |
| 830 | status_line->first_line[first_line_len] = '\0'; | 835 | status_line->first_line[first_line_len] = '\0'; |
| 831 | char *first_line_buf = strdup(status_line->first_line); | 836 | char *first_line_buf = strdup(status_line->first_line); |
| @@ -833,23 +838,34 @@ int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) | |||
| 833 | /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */ | 838 | /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */ |
| 834 | char *temp_string = strtok(first_line_buf, "/"); | 839 | char *temp_string = strtok(first_line_buf, "/"); |
| 835 | if (temp_string == NULL) { | 840 | if (temp_string == NULL) { |
| 841 | if (verbose > 1) { | ||
| 842 | printf("%s: no / found\n", __func__); | ||
| 843 | } | ||
| 836 | free(first_line_buf); | 844 | free(first_line_buf); |
| 837 | return -1; | 845 | return -1; |
| 838 | } | 846 | } |
| 847 | |||
| 839 | if (strcmp(temp_string, "HTTP") != 0) { | 848 | if (strcmp(temp_string, "HTTP") != 0) { |
| 849 | if (verbose > 1) { | ||
| 850 | printf("%s: string 'HTTP' not found\n", __func__); | ||
| 851 | } | ||
| 840 | free(first_line_buf); | 852 | free(first_line_buf); |
| 841 | return -1; | 853 | return -1; |
| 842 | } | 854 | } |
| 843 | 855 | ||
| 856 | // try to find a space in the remaining string? | ||
| 857 | // the space after HTTP/1.1 probably | ||
| 844 | temp_string = strtok(NULL, " "); | 858 | temp_string = strtok(NULL, " "); |
| 845 | if (temp_string == NULL) { | 859 | if (temp_string == NULL) { |
| 860 | if (verbose > 1) { | ||
| 861 | printf("%s: no space after protocol definition\n", __func__); | ||
| 862 | } | ||
| 846 | free(first_line_buf); | 863 | free(first_line_buf); |
| 847 | return -1; | 864 | return -1; |
| 848 | } | 865 | } |
| 849 | 866 | ||
| 850 | char *temp_string_2; | 867 | char *temp_string_2; |
| 851 | if (strchr(temp_string, '.') != NULL) { | 868 | if (strchr(temp_string, '.') != NULL) { |
| 852 | |||
| 853 | /* HTTP 1.x case */ | 869 | /* HTTP 1.x case */ |
| 854 | strtok(temp_string, "."); | 870 | strtok(temp_string, "."); |
| 855 | status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10); | 871 | status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10); |
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c index 468ded31..9bc68eb3 100644 --- a/plugins/check_dbi.c +++ b/plugins/check_dbi.c | |||
| @@ -34,6 +34,10 @@ const char *copyright = "2011-2024"; | |||
| 34 | const char *email = "devel@monitoring-plugins.org"; | 34 | const char *email = "devel@monitoring-plugins.org"; |
| 35 | 35 | ||
| 36 | #include "../lib/monitoringplug.h" | 36 | #include "../lib/monitoringplug.h" |
| 37 | #include "thresholds.h" | ||
| 38 | #include "perfdata.h" | ||
| 39 | #include "output.h" | ||
| 40 | #include "states.h" | ||
| 37 | #include "check_dbi.d/config.h" | 41 | #include "check_dbi.d/config.h" |
| 38 | #include "common.h" | 42 | #include "common.h" |
| 39 | #include "utils.h" | 43 | #include "utils.h" |
| @@ -63,7 +67,6 @@ typedef struct { | |||
| 63 | } check_dbi_config_wrapper; | 67 | } check_dbi_config_wrapper; |
| 64 | 68 | ||
| 65 | static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); | 69 | static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); |
| 66 | static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/); | ||
| 67 | void print_usage(void); | 70 | void print_usage(void); |
| 68 | static void print_help(void); | 71 | static void print_help(void); |
| 69 | 72 | ||
| @@ -71,26 +74,18 @@ static double timediff(struct timeval /*start*/, struct timeval /*end*/); | |||
| 71 | 74 | ||
| 72 | static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...); | 75 | static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...); |
| 73 | 76 | ||
| 74 | static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, | 77 | typedef struct { |
| 75 | double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/, | 78 | char *result_string; |
| 76 | mp_dbi_type /*type*/, char * /*np_dbi_query*/); | 79 | double result_number; |
| 80 | double query_duration; | ||
| 81 | int error_code; | ||
| 82 | const char *error_string; | ||
| 83 | mp_state_enum query_processing_status; | ||
| 84 | } do_query_result; | ||
| 85 | static do_query_result do_query(dbi_conn conn, check_dbi_metric metric, check_dbi_type type, | ||
| 86 | char *query); | ||
| 77 | 87 | ||
| 78 | int main(int argc, char **argv) { | 88 | int main(int argc, char **argv) { |
| 79 | int status = STATE_UNKNOWN; | ||
| 80 | |||
| 81 | dbi_driver driver; | ||
| 82 | dbi_conn conn; | ||
| 83 | |||
| 84 | unsigned int server_version; | ||
| 85 | |||
| 86 | struct timeval start_timeval; | ||
| 87 | struct timeval end_timeval; | ||
| 88 | double conn_time = 0.0; | ||
| 89 | double query_time = 0.0; | ||
| 90 | |||
| 91 | const char *query_val_str = NULL; | ||
| 92 | double query_val = 0.0; | ||
| 93 | |||
| 94 | setlocale(LC_ALL, ""); | 89 | setlocale(LC_ALL, ""); |
| 95 | bindtextdomain(PACKAGE, LOCALEDIR); | 90 | bindtextdomain(PACKAGE, LOCALEDIR); |
| 96 | textdomain(PACKAGE); | 91 | textdomain(PACKAGE); |
| @@ -106,6 +101,10 @@ int main(int argc, char **argv) { | |||
| 106 | 101 | ||
| 107 | const check_dbi_config config = tmp.config; | 102 | const check_dbi_config config = tmp.config; |
| 108 | 103 | ||
| 104 | if (config.output_format_is_set) { | ||
| 105 | mp_set_format(config.output_format); | ||
| 106 | } | ||
| 107 | |||
| 109 | /* Set signal handling and alarm */ | 108 | /* Set signal handling and alarm */ |
| 110 | if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { | 109 | if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { |
| 111 | usage4(_("Cannot catch SIGALRM")); | 110 | usage4(_("Cannot catch SIGALRM")); |
| @@ -116,44 +115,46 @@ int main(int argc, char **argv) { | |||
| 116 | printf("Initializing DBI\n"); | 115 | printf("Initializing DBI\n"); |
| 117 | } | 116 | } |
| 118 | 117 | ||
| 119 | dbi_inst *instance_p = {0}; | 118 | dbi_inst instance_p = NULL; |
| 120 | 119 | if (dbi_initialize_r(NULL, &instance_p) < 0) { | |
| 121 | if (dbi_initialize_r(NULL, instance_p) < 0) { | 120 | printf("failed to initialize DBI; possibly you don't have any drivers installed.\n"); |
| 122 | printf( | 121 | exit(STATE_UNKNOWN); |
| 123 | "UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n"); | ||
| 124 | return STATE_UNKNOWN; | ||
| 125 | } | 122 | } |
| 126 | 123 | ||
| 124 | // Try to prevent libdbi from printing stuff on stderr | ||
| 125 | // Who thought that would be a good idea anyway? | ||
| 126 | dbi_set_verbosity_r(0, instance_p); | ||
| 127 | |||
| 127 | if (instance_p == NULL) { | 128 | if (instance_p == NULL) { |
| 128 | printf("UNKNOWN - failed to initialize DBI.\n"); | 129 | printf("failed to initialize DBI.\n"); |
| 129 | return STATE_UNKNOWN; | 130 | exit(STATE_UNKNOWN); |
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | if (verbose) { | 133 | if (verbose) { |
| 133 | printf("Opening DBI driver '%s'\n", config.dbi_driver); | 134 | printf("Opening DBI driver '%s'\n", config.dbi_driver); |
| 134 | } | 135 | } |
| 135 | 136 | ||
| 136 | driver = dbi_driver_open_r(config.dbi_driver, instance_p); | 137 | dbi_driver driver = dbi_driver_open_r(config.dbi_driver, instance_p); |
| 137 | if (!driver) { | 138 | if (!driver) { |
| 138 | printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", | 139 | printf("failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver); |
| 139 | config.dbi_driver); | ||
| 140 | 140 | ||
| 141 | printf("Known drivers:\n"); | 141 | printf("Known drivers:\n"); |
| 142 | for (driver = dbi_driver_list_r(NULL, instance_p); driver; | 142 | for (driver = dbi_driver_list_r(NULL, instance_p); driver; |
| 143 | driver = dbi_driver_list_r(driver, instance_p)) { | 143 | driver = dbi_driver_list_r(driver, instance_p)) { |
| 144 | printf(" - %s\n", dbi_driver_get_name(driver)); | 144 | printf(" - %s\n", dbi_driver_get_name(driver)); |
| 145 | } | 145 | } |
| 146 | return STATE_UNKNOWN; | 146 | exit(STATE_UNKNOWN); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | /* make a connection to the database */ | 149 | /* make a connection to the database */ |
| 150 | struct timeval start_timeval; | ||
| 150 | gettimeofday(&start_timeval, NULL); | 151 | gettimeofday(&start_timeval, NULL); |
| 151 | 152 | ||
| 152 | conn = dbi_conn_open(driver); | 153 | dbi_conn conn = dbi_conn_open(driver); |
| 153 | if (!conn) { | 154 | if (!conn) { |
| 154 | printf("UNKNOWN - failed top open connection object.\n"); | 155 | printf("UNKNOWN - failed top open connection object.\n"); |
| 155 | dbi_conn_close(conn); | 156 | dbi_conn_close(conn); |
| 156 | return STATE_UNKNOWN; | 157 | exit(STATE_UNKNOWN); |
| 157 | } | 158 | } |
| 158 | 159 | ||
| 159 | for (size_t i = 0; i < config.dbi_options_num; ++i) { | 160 | for (size_t i = 0; i < config.dbi_options_num; ++i) { |
| @@ -167,10 +168,10 @@ int main(int argc, char **argv) { | |||
| 167 | if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) { | 168 | if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) { |
| 168 | continue; | 169 | continue; |
| 169 | } | 170 | } |
| 170 | /* else: status != 0 */ | ||
| 171 | 171 | ||
| 172 | np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", | 172 | // Failing to set option |
| 173 | config.dbi_options[i].key, config.dbi_options[i].value); | 173 | np_dbi_print_error(conn, "failed to set option '%s' to '%s'", config.dbi_options[i].key, |
| 174 | config.dbi_options[i].value); | ||
| 174 | printf("Known driver options:\n"); | 175 | printf("Known driver options:\n"); |
| 175 | 176 | ||
| 176 | for (opt = dbi_conn_get_option_list(conn, NULL); opt; | 177 | for (opt = dbi_conn_get_option_list(conn, NULL); opt; |
| @@ -178,7 +179,7 @@ int main(int argc, char **argv) { | |||
| 178 | printf(" - %s\n", opt); | 179 | printf(" - %s\n", opt); |
| 179 | } | 180 | } |
| 180 | dbi_conn_close(conn); | 181 | dbi_conn_close(conn); |
| 181 | return STATE_UNKNOWN; | 182 | exit(STATE_UNKNOWN); |
| 182 | } | 183 | } |
| 183 | 184 | ||
| 184 | if (config.host) { | 185 | if (config.host) { |
| @@ -206,80 +207,216 @@ int main(int argc, char **argv) { | |||
| 206 | } | 207 | } |
| 207 | 208 | ||
| 208 | if (dbi_conn_connect(conn) < 0) { | 209 | if (dbi_conn_connect(conn) < 0) { |
| 209 | np_dbi_print_error(conn, "UNKNOWN - failed to connect to database"); | 210 | np_dbi_print_error(conn, "failed to connect to database"); |
| 210 | return STATE_UNKNOWN; | 211 | exit(STATE_UNKNOWN); |
| 211 | } | 212 | } |
| 212 | 213 | ||
| 214 | struct timeval end_timeval; | ||
| 213 | gettimeofday(&end_timeval, NULL); | 215 | gettimeofday(&end_timeval, NULL); |
| 214 | conn_time = timediff(start_timeval, end_timeval); | 216 | double conn_time = timediff(start_timeval, end_timeval); |
| 215 | |||
| 216 | server_version = dbi_conn_get_engine_version(conn); | ||
| 217 | if (verbose) { | 217 | if (verbose) { |
| 218 | printf("Connected to server version %u\n", server_version); | 218 | printf("Time elapsed: %f\n", conn_time); |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | if (config.metric == METRIC_SERVER_VERSION) { | 221 | mp_check overall = mp_check_init(); |
| 222 | status = get_status(server_version, config.dbi_thresholds); | 222 | |
| 223 | mp_subcheck sc_connection_time = mp_subcheck_init(); | ||
| 224 | sc_connection_time = mp_set_subcheck_default_state(sc_connection_time, STATE_OK); | ||
| 225 | xasprintf(&sc_connection_time.output, "Connection time: %f", conn_time); | ||
| 226 | |||
| 227 | mp_perfdata pd_conn_duration = perfdata_init(); | ||
| 228 | pd_conn_duration.label = "conntime"; | ||
| 229 | pd_conn_duration = mp_set_pd_value(pd_conn_duration, conn_time); | ||
| 230 | |||
| 231 | if (config.metric == METRIC_CONN_TIME) { | ||
| 232 | pd_conn_duration = mp_pd_set_thresholds(pd_conn_duration, config.thresholds); | ||
| 233 | mp_state_enum status = mp_get_pd_status(pd_conn_duration); | ||
| 234 | sc_connection_time = mp_set_subcheck_state(sc_connection_time, status); | ||
| 235 | if (status != STATE_OK) { | ||
| 236 | xasprintf(&sc_connection_time.output, "%s violates thresholds", | ||
| 237 | sc_connection_time.output); | ||
| 238 | } | ||
| 223 | } | 239 | } |
| 224 | 240 | ||
| 241 | mp_add_perfdata_to_subcheck(&sc_connection_time, pd_conn_duration); | ||
| 242 | mp_add_subcheck_to_check(&overall, sc_connection_time); | ||
| 243 | |||
| 244 | unsigned int server_version = dbi_conn_get_engine_version(conn); | ||
| 225 | if (verbose) { | 245 | if (verbose) { |
| 226 | printf("Time elapsed: %f\n", conn_time); | 246 | printf("Connected to server version %u\n", server_version); |
| 227 | } | 247 | } |
| 228 | 248 | ||
| 229 | if (config.metric == METRIC_CONN_TIME) { | 249 | mp_subcheck sc_server_version = mp_subcheck_init(); |
| 230 | status = get_status(conn_time, config.dbi_thresholds); | 250 | sc_server_version = mp_set_subcheck_default_state(sc_server_version, STATE_OK); |
| 231 | } | 251 | xasprintf(&sc_server_version.output, "Connected to server version %u", server_version); |
| 252 | |||
| 253 | if (config.metric == METRIC_SERVER_VERSION) { | ||
| 254 | mp_perfdata pd_server_version = perfdata_init(); | ||
| 255 | pd_server_version = mp_set_pd_value(pd_server_version, server_version); | ||
| 256 | pd_server_version = mp_pd_set_thresholds(pd_server_version, config.thresholds); | ||
| 257 | mp_state_enum status = mp_get_pd_status(pd_server_version); | ||
| 258 | mp_add_perfdata_to_subcheck(&sc_server_version, pd_server_version); | ||
| 259 | |||
| 260 | sc_server_version = mp_set_subcheck_state(sc_server_version, status); | ||
| 261 | |||
| 262 | if (status != STATE_OK) { | ||
| 263 | xasprintf(&sc_server_version.output, "%s violates thresholds", | ||
| 264 | sc_server_version.output); | ||
| 265 | } | ||
| 266 | }; | ||
| 267 | mp_add_subcheck_to_check(&overall, sc_server_version); | ||
| 232 | 268 | ||
| 233 | /* select a database */ | 269 | /* select a database */ |
| 234 | if (config.dbi_database) { | 270 | if (config.database) { |
| 235 | if (verbose > 1) { | 271 | if (verbose > 1) { |
| 236 | printf("Selecting database '%s'\n", config.dbi_database); | 272 | printf("Selecting database '%s'\n", config.database); |
| 237 | } | 273 | } |
| 238 | 274 | ||
| 239 | if (dbi_conn_select_db(conn, config.dbi_database)) { | 275 | mp_subcheck sc_select_db = mp_subcheck_init(); |
| 240 | np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", | 276 | sc_select_db = mp_set_subcheck_default_state(sc_select_db, STATE_OK); |
| 241 | config.dbi_database); | 277 | |
| 242 | return STATE_UNKNOWN; | 278 | if (dbi_conn_select_db(conn, config.database)) { |
| 279 | np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.database); | ||
| 280 | exit(STATE_UNKNOWN); | ||
| 281 | } else { | ||
| 282 | mp_add_subcheck_to_check(&overall, sc_select_db); | ||
| 243 | } | 283 | } |
| 244 | } | 284 | } |
| 245 | 285 | ||
| 246 | if (config.dbi_query) { | 286 | // Do a query (if configured) |
| 287 | if (config.query) { | ||
| 288 | mp_subcheck sc_query = mp_subcheck_init(); | ||
| 289 | sc_query = mp_set_subcheck_default_state(sc_query, STATE_UNKNOWN); | ||
| 290 | |||
| 247 | /* execute query */ | 291 | /* execute query */ |
| 248 | status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, | 292 | do_query_result query_res = do_query(conn, config.metric, config.type, config.query); |
| 249 | config.dbi_query); | 293 | |
| 250 | if (status != STATE_OK) { | 294 | if (query_res.error_code != 0) { |
| 251 | /* do_query prints an error message in this case */ | 295 | xasprintf(&sc_query.output, "Query failed: %s", query_res.error_string); |
| 252 | return status; | 296 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); |
| 253 | } | 297 | } else if (query_res.query_processing_status != STATE_OK) { |
| 298 | if (query_res.error_string) { | ||
| 299 | xasprintf(&sc_query.output, "Failed to process query: %s", query_res.error_string); | ||
| 300 | } else { | ||
| 301 | xasprintf(&sc_query.output, "Failed to process query"); | ||
| 302 | } | ||
| 303 | sc_query = mp_set_subcheck_state(sc_query, query_res.query_processing_status); | ||
| 304 | } else { | ||
| 305 | // query succeeded in general | ||
| 306 | xasprintf(&sc_query.output, "Query '%s' succeeded", config.query); | ||
| 307 | |||
| 308 | // that's a OK by default now | ||
| 309 | sc_query = mp_set_subcheck_default_state(sc_query, STATE_OK); | ||
| 310 | |||
| 311 | // query duration first | ||
| 312 | mp_perfdata pd_query_duration = perfdata_init(); | ||
| 313 | pd_query_duration = mp_set_pd_value(pd_query_duration, query_res.query_duration); | ||
| 314 | pd_query_duration.label = "querytime"; | ||
| 315 | if (config.metric == METRIC_QUERY_TIME) { | ||
| 316 | pd_query_duration = mp_pd_set_thresholds(pd_query_duration, config.thresholds); | ||
| 317 | } | ||
| 318 | |||
| 319 | mp_add_perfdata_to_subcheck(&sc_query, pd_query_duration); | ||
| 254 | 320 | ||
| 255 | if (config.metric == METRIC_QUERY_RESULT) { | 321 | if (config.metric == METRIC_QUERY_RESULT) { |
| 256 | if (config.expect) { | 322 | if (config.expect) { |
| 257 | if ((!query_val_str) || strcmp(query_val_str, config.expect)) { | 323 | if ((!query_res.result_string) || |
| 258 | status = STATE_CRITICAL; | 324 | strcmp(query_res.result_string, config.expect)) { |
| 325 | xasprintf(&sc_query.output, "Found string '%s' in query result", | ||
| 326 | config.expect); | ||
| 327 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 328 | } else { | ||
| 329 | xasprintf(&sc_query.output, "Did not find string '%s' in query result", | ||
| 330 | config.expect); | ||
| 331 | sc_query = mp_set_subcheck_state(sc_query, STATE_OK); | ||
| 332 | } | ||
| 333 | } else if (config.expect_re_str) { | ||
| 334 | int comp_err; | ||
| 335 | regex_t expect_re = {}; | ||
| 336 | comp_err = regcomp(&expect_re, config.expect_re_str, config.expect_re_cflags); | ||
| 337 | if (comp_err != 0) { | ||
| 338 | // TODO error, failed to compile regex | ||
| 339 | // TODO move this to config sanitatisation | ||
| 340 | printf("Failed to compile regex from string '%s'", config.expect_re_str); | ||
| 341 | exit(STATE_UNKNOWN); | ||
| 342 | } | ||
| 343 | |||
| 344 | int err = | ||
| 345 | regexec(&expect_re, query_res.result_string, 0, NULL, /* flags = */ 0); | ||
| 346 | if (!err) { | ||
| 347 | sc_query = mp_set_subcheck_state(sc_query, STATE_OK); | ||
| 348 | xasprintf(&sc_query.output, "Found regular expression '%s' in query result", | ||
| 349 | config.expect_re_str); | ||
| 350 | } else if (err == REG_NOMATCH) { | ||
| 351 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 352 | xasprintf(&sc_query.output, | ||
| 353 | "Did not find regular expression '%s' in query result", | ||
| 354 | config.expect_re_str); | ||
| 355 | } else { | ||
| 356 | char errmsg[1024]; | ||
| 357 | regerror(err, &expect_re, errmsg, sizeof(errmsg)); | ||
| 358 | xasprintf(&sc_query.output, | ||
| 359 | "ERROR - failed to execute regular expression: %s\n", errmsg); | ||
| 360 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 361 | } | ||
| 259 | } else { | 362 | } else { |
| 260 | status = STATE_OK; | 363 | // no string matching |
| 364 | if (isnan(query_res.result_number)) { | ||
| 365 | // The query result is not a number, but no string checking was configured | ||
| 366 | // so we expected a number | ||
| 367 | // this is a CRITICAL | ||
| 368 | xasprintf(&sc_query.output, "Query '%s' result is not numeric", | ||
| 369 | config.query); | ||
| 370 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 371 | |||
| 372 | } else { | ||
| 373 | |||
| 374 | mp_perfdata pd_query_val = perfdata_init(); | ||
| 375 | pd_query_val = mp_set_pd_value(pd_query_val, query_res.result_number); | ||
| 376 | pd_query_val.label = "query"; | ||
| 377 | pd_query_val = mp_pd_set_thresholds(pd_query_val, config.thresholds); | ||
| 378 | |||
| 379 | mp_add_perfdata_to_subcheck(&sc_query, pd_query_val); | ||
| 380 | mp_state_enum query_numerical_result = mp_get_pd_status(pd_query_val); | ||
| 381 | |||
| 382 | sc_query = mp_set_subcheck_state(sc_query, query_numerical_result); | ||
| 383 | // TODO set pd thresholds | ||
| 384 | // if (config.dbi_thresholds->warning) { | ||
| 385 | // pd_query_val.warn= config.dbi_thresholds->warning | ||
| 386 | // } else { | ||
| 387 | // } | ||
| 388 | |||
| 389 | if (query_numerical_result == STATE_OK) { | ||
| 390 | xasprintf(&sc_query.output, | ||
| 391 | "Query result '%f' is within given thresholds", | ||
| 392 | query_res.result_number); | ||
| 393 | } else { | ||
| 394 | xasprintf(&sc_query.output, | ||
| 395 | "Query result '%f' violates the given thresholds", | ||
| 396 | query_res.result_number); | ||
| 397 | } | ||
| 398 | } | ||
| 261 | } | 399 | } |
| 262 | } else if (config.expect_re_str) { | 400 | } else if (config.metric == METRIC_QUERY_TIME) { |
| 263 | int err; | 401 | mp_state_enum query_time_status = mp_get_pd_status(pd_query_duration); |
| 264 | 402 | mp_set_subcheck_state(sc_query, query_time_status); | |
| 265 | regex_t expect_re = {}; | 403 | |
| 266 | err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0); | 404 | if (query_time_status == STATE_OK) { |
| 267 | if (!err) { | 405 | xasprintf(&sc_query.output, "Query duration '%f' is within given thresholds", |
| 268 | status = STATE_OK; | 406 | query_res.query_duration); |
| 269 | } else if (err == REG_NOMATCH) { | ||
| 270 | status = STATE_CRITICAL; | ||
| 271 | } else { | 407 | } else { |
| 272 | char errmsg[1024]; | 408 | xasprintf(&sc_query.output, "Query duration '%f' violates the given thresholds", |
| 273 | regerror(err, &expect_re, errmsg, sizeof(errmsg)); | 409 | query_res.query_duration); |
| 274 | printf("ERROR - failed to execute regular expression: %s\n", errmsg); | ||
| 275 | status = STATE_CRITICAL; | ||
| 276 | } | 410 | } |
| 277 | } else { | 411 | } else { |
| 278 | status = get_status(query_val, config.dbi_thresholds); | 412 | /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error |
| 413 | * which should have been reported and handled (abort) before | ||
| 414 | * ... unless we expected a string to be returned */ | ||
| 415 | assert((!isnan(query_res.result_number)) || (config.type == TYPE_STRING)); | ||
| 279 | } | 416 | } |
| 280 | } else if (config.metric == METRIC_QUERY_TIME) { | ||
| 281 | status = get_status(query_time, config.dbi_thresholds); | ||
| 282 | } | 417 | } |
| 418 | |||
| 419 | mp_add_subcheck_to_check(&overall, sc_query); | ||
| 283 | } | 420 | } |
| 284 | 421 | ||
| 285 | if (verbose) { | 422 | if (verbose) { |
| @@ -287,71 +424,17 @@ int main(int argc, char **argv) { | |||
| 287 | } | 424 | } |
| 288 | dbi_conn_close(conn); | 425 | dbi_conn_close(conn); |
| 289 | 426 | ||
| 290 | /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error | 427 | mp_exit(overall); |
| 291 | * which should have been reported and handled (abort) before | ||
| 292 | * ... unless we expected a string to be returned */ | ||
| 293 | assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || | ||
| 294 | (config.type == TYPE_STRING)); | ||
| 295 | |||
| 296 | assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str)); | ||
| 297 | |||
| 298 | printf("%s - connection time: %fs", state_text(status), conn_time); | ||
| 299 | if (config.dbi_query) { | ||
| 300 | if (config.type == TYPE_STRING) { | ||
| 301 | assert(config.expect || config.expect_re_str); | ||
| 302 | printf(", '%s' returned '%s' in %fs", config.dbi_query, | ||
| 303 | query_val_str ? query_val_str : "<nothing>", query_time); | ||
| 304 | if (status != STATE_OK) { | ||
| 305 | if (config.expect) { | ||
| 306 | printf(" (expected '%s')", config.expect); | ||
| 307 | } else if (config.expect_re_str) { | ||
| 308 | printf(" (expected regex /%s/%s)", config.expect_re_str, | ||
| 309 | ((config.expect_re_cflags & REG_ICASE) ? "i" : "")); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | } else if (isnan(query_val)) { | ||
| 313 | printf(", '%s' query execution time: %fs", config.dbi_query, query_time); | ||
| 314 | } else { | ||
| 315 | printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | printf( | ||
| 320 | " | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, | ||
| 321 | ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "", | ||
| 322 | ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", | ||
| 323 | server_version, | ||
| 324 | ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range | ||
| 325 | : "", | ||
| 326 | ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range | ||
| 327 | : ""); | ||
| 328 | if (config.dbi_query) { | ||
| 329 | if (!isnan(query_val)) { /* this is also true when -e is used */ | ||
| 330 | printf(" query=%f;%s;%s;;", query_val, | ||
| 331 | ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) | ||
| 332 | ? config.warning_range | ||
| 333 | : "", | ||
| 334 | ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) | ||
| 335 | ? config.critical_range | ||
| 336 | : ""); | ||
| 337 | } | ||
| 338 | printf(" querytime=%fs;%s;%s;0;", query_time, | ||
| 339 | ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range | ||
| 340 | : "", | ||
| 341 | ((config.metric == METRIC_QUERY_TIME) && config.critical_range) | ||
| 342 | ? config.critical_range | ||
| 343 | : ""); | ||
| 344 | } | ||
| 345 | printf("\n"); | ||
| 346 | return status; | ||
| 347 | } | 428 | } |
| 348 | 429 | ||
| 349 | /* process command-line arguments */ | 430 | /* process command-line arguments */ |
| 350 | check_dbi_config_wrapper process_arguments(int argc, char **argv) { | 431 | check_dbi_config_wrapper process_arguments(int argc, char **argv) { |
| 432 | enum { | ||
| 433 | output_format_index = CHAR_MAX + 1, | ||
| 434 | }; | ||
| 351 | 435 | ||
| 352 | int option = 0; | 436 | int option = 0; |
| 353 | static struct option longopts[] = {STD_LONG_OPTS, | 437 | static struct option longopts[] = {STD_LONG_OPTS, |
| 354 | |||
| 355 | {"expect", required_argument, 0, 'e'}, | 438 | {"expect", required_argument, 0, 'e'}, |
| 356 | {"regex", required_argument, 0, 'r'}, | 439 | {"regex", required_argument, 0, 'r'}, |
| 357 | {"regexi", required_argument, 0, 'R'}, | 440 | {"regexi", required_argument, 0, 'R'}, |
| @@ -360,6 +443,7 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) { | |||
| 360 | {"option", required_argument, 0, 'o'}, | 443 | {"option", required_argument, 0, 'o'}, |
| 361 | {"query", required_argument, 0, 'q'}, | 444 | {"query", required_argument, 0, 'q'}, |
| 362 | {"database", required_argument, 0, 'D'}, | 445 | {"database", required_argument, 0, 'D'}, |
| 446 | {"output-format", required_argument, 0, output_format_index}, | ||
| 363 | {0, 0, 0, 0}}; | 447 | {0, 0, 0, 0}}; |
| 364 | 448 | ||
| 365 | check_dbi_config_wrapper result = { | 449 | check_dbi_config_wrapper result = { |
| @@ -384,14 +468,22 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) { | |||
| 384 | print_revision(progname, NP_VERSION); | 468 | print_revision(progname, NP_VERSION); |
| 385 | exit(STATE_UNKNOWN); | 469 | exit(STATE_UNKNOWN); |
| 386 | 470 | ||
| 387 | case 'c': /* critical range */ | 471 | case 'c': /* critical range */ { |
| 388 | result.config.critical_range = optarg; | 472 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 473 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 474 | die(STATE_UNKNOWN, "failed to parse critical threshold"); | ||
| 475 | } | ||
| 476 | result.config.thresholds = mp_thresholds_set_crit(result.config.thresholds, tmp.range); | ||
| 389 | result.config.type = TYPE_NUMERIC; | 477 | result.config.type = TYPE_NUMERIC; |
| 390 | break; | 478 | } break; |
| 391 | case 'w': /* warning range */ | 479 | case 'w': /* warning range */ { |
| 392 | result.config.warning_range = optarg; | 480 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 481 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 482 | die(STATE_UNKNOWN, "failed to parse warning threshold"); | ||
| 483 | } | ||
| 484 | result.config.thresholds = mp_thresholds_set_warn(result.config.thresholds, tmp.range); | ||
| 393 | result.config.type = TYPE_NUMERIC; | 485 | result.config.type = TYPE_NUMERIC; |
| 394 | break; | 486 | } break; |
| 395 | case 'e': | 487 | case 'e': |
| 396 | result.config.expect = optarg; | 488 | result.config.expect = optarg; |
| 397 | result.config.type = TYPE_STRING; | 489 | result.config.type = TYPE_STRING; |
| @@ -418,7 +510,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) { | |||
| 418 | } | 510 | } |
| 419 | break; | 511 | break; |
| 420 | } | 512 | } |
| 421 | |||
| 422 | case 'm': | 513 | case 'm': |
| 423 | if (!strcasecmp(optarg, "CONN_TIME")) { | 514 | if (!strcasecmp(optarg, "CONN_TIME")) { |
| 424 | result.config.metric = METRIC_CONN_TIME; | 515 | result.config.metric = METRIC_CONN_TIME; |
| @@ -438,7 +529,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) { | |||
| 438 | } else { | 529 | } else { |
| 439 | timeout_interval = atoi(optarg); | 530 | timeout_interval = atoi(optarg); |
| 440 | } | 531 | } |
| 441 | |||
| 442 | break; | 532 | break; |
| 443 | case 'H': /* host */ | 533 | case 'H': /* host */ |
| 444 | if (!is_host(optarg)) { | 534 | if (!is_host(optarg)) { |
| @@ -450,7 +540,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) { | |||
| 450 | case 'v': | 540 | case 'v': |
| 451 | verbose++; | 541 | verbose++; |
| 452 | break; | 542 | break; |
| 453 | |||
| 454 | case 'd': | 543 | case 'd': |
| 455 | result.config.dbi_driver = optarg; | 544 | result.config.dbi_driver = optarg; |
| 456 | break; | 545 | break; |
| @@ -482,61 +571,68 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) { | |||
| 482 | new->value = value; | 571 | new->value = value; |
| 483 | } break; | 572 | } break; |
| 484 | case 'q': | 573 | case 'q': |
| 485 | result.config.dbi_query = optarg; | 574 | result.config.query = optarg; |
| 486 | break; | 575 | break; |
| 487 | case 'D': | 576 | case 'D': |
| 488 | result.config.dbi_database = optarg; | 577 | result.config.database = optarg; |
| 578 | break; | ||
| 579 | case output_format_index: { | ||
| 580 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 581 | if (!parser.parsing_success) { | ||
| 582 | // TODO List all available formats here, maybe add anothoer usage function | ||
| 583 | printf("Invalid output format: %s\n", optarg); | ||
| 584 | exit(STATE_UNKNOWN); | ||
| 585 | } | ||
| 586 | |||
| 587 | result.config.output_format_is_set = true; | ||
| 588 | result.config.output_format = parser.output_format; | ||
| 489 | break; | 589 | break; |
| 490 | } | 590 | } |
| 591 | } | ||
| 491 | } | 592 | } |
| 492 | 593 | ||
| 493 | set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, | 594 | if (!result.config.dbi_driver) { |
| 494 | result.config.critical_range); | ||
| 495 | |||
| 496 | return validate_arguments(result); | ||
| 497 | } | ||
| 498 | |||
| 499 | check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) { | ||
| 500 | if (!config_wrapper.config.dbi_driver) { | ||
| 501 | usage("Must specify a DBI driver"); | 595 | usage("Must specify a DBI driver"); |
| 502 | } | 596 | } |
| 503 | 597 | ||
| 504 | if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || | 598 | if (((result.config.metric == METRIC_QUERY_RESULT) || |
| 505 | (config_wrapper.config.metric == METRIC_QUERY_TIME)) && | 599 | (result.config.metric == METRIC_QUERY_TIME)) && |
| 506 | (!config_wrapper.config.dbi_query)) { | 600 | (!result.config.query)) { |
| 507 | usage("Must specify a query to execute (metric == QUERY_RESULT)"); | 601 | usage("Must specify a query to execute (metric == QUERY_RESULT)"); |
| 508 | } | 602 | } |
| 509 | 603 | ||
| 510 | if ((config_wrapper.config.metric != METRIC_CONN_TIME) && | 604 | if ((result.config.metric != METRIC_CONN_TIME) && |
| 511 | (config_wrapper.config.metric != METRIC_SERVER_VERSION) && | 605 | (result.config.metric != METRIC_SERVER_VERSION) && |
| 512 | (config_wrapper.config.metric != METRIC_QUERY_RESULT) && | 606 | (result.config.metric != METRIC_QUERY_RESULT) && |
| 513 | (config_wrapper.config.metric != METRIC_QUERY_TIME)) { | 607 | (result.config.metric != METRIC_QUERY_TIME)) { |
| 514 | usage("Invalid metric specified"); | 608 | usage("Invalid metric specified"); |
| 515 | } | 609 | } |
| 516 | 610 | ||
| 517 | if (config_wrapper.config.expect && | 611 | if (result.config.expect && |
| 518 | (config_wrapper.config.warning_range || config_wrapper.config.critical_range || | 612 | (result.config.thresholds.warning_is_set || result.config.thresholds.critical_is_set || |
| 519 | config_wrapper.config.expect_re_str)) { | 613 | result.config.expect_re_str)) { |
| 520 | usage("Do not mix -e and -w/-c/-r/-R"); | 614 | usage("Do not mix -e and -w/-c/-r/-R"); |
| 521 | } | 615 | } |
| 522 | 616 | ||
| 523 | if (config_wrapper.config.expect_re_str && | 617 | if (result.config.expect_re_str && |
| 524 | (config_wrapper.config.warning_range || config_wrapper.config.critical_range || | 618 | (result.config.thresholds.warning_is_set || result.config.thresholds.critical_is_set || |
| 525 | config_wrapper.config.expect)) { | 619 | result.config.expect)) { |
| 526 | usage("Do not mix -r/-R and -w/-c/-e"); | 620 | usage("Do not mix -r/-R and -w/-c/-e"); |
| 527 | } | 621 | } |
| 528 | 622 | ||
| 529 | if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) { | 623 | if (result.config.expect && (result.config.metric != METRIC_QUERY_RESULT)) { |
| 530 | usage("Option -e requires metric QUERY_RESULT"); | 624 | usage("Option -e requires metric QUERY_RESULT"); |
| 531 | } | 625 | } |
| 532 | 626 | ||
| 533 | if (config_wrapper.config.expect_re_str && | 627 | if (result.config.expect_re_str && (result.config.metric != METRIC_QUERY_RESULT)) { |
| 534 | (config_wrapper.config.metric != METRIC_QUERY_RESULT)) { | ||
| 535 | usage("Options -r/-R require metric QUERY_RESULT"); | 628 | usage("Options -r/-R require metric QUERY_RESULT"); |
| 536 | } | 629 | } |
| 537 | 630 | ||
| 538 | config_wrapper.errorcode = OK; | 631 | if (result.config.type == TYPE_STRING) { |
| 539 | return config_wrapper; | 632 | assert(result.config.expect || result.config.expect_re_str); |
| 633 | } | ||
| 634 | |||
| 635 | return result; | ||
| 540 | } | 636 | } |
| 541 | 637 | ||
| 542 | void print_help(void) { | 638 | void print_help(void) { |
| @@ -642,21 +738,12 @@ void print_usage(void) { | |||
| 642 | printf(" [-e <string>] [-r|-R <regex>]\n"); | 738 | printf(" [-e <string>] [-r|-R <regex>]\n"); |
| 643 | } | 739 | } |
| 644 | 740 | ||
| 645 | const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type, | 741 | const char *get_field_str(dbi_result res, check_dbi_metric metric, check_dbi_type type) { |
| 646 | mp_dbi_metric metric, mp_dbi_type type) { | 742 | const char *str = dbi_result_get_string_idx(res, 1); |
| 647 | const char *str; | ||
| 648 | |||
| 649 | if (field_type != DBI_TYPE_STRING) { | ||
| 650 | printf("CRITICAL - result value is not a string\n"); | ||
| 651 | return NULL; | ||
| 652 | } | ||
| 653 | |||
| 654 | str = dbi_result_get_string_idx(res, 1); | ||
| 655 | if ((!str) || (strcmp(str, "ERROR") == 0)) { | 743 | if ((!str) || (strcmp(str, "ERROR") == 0)) { |
| 656 | if (metric != METRIC_QUERY_RESULT) { | 744 | if (metric != METRIC_QUERY_RESULT) { |
| 657 | return NULL; | 745 | return NULL; |
| 658 | } | 746 | } |
| 659 | np_dbi_print_error(conn, "CRITICAL - failed to fetch string value"); | ||
| 660 | return NULL; | 747 | return NULL; |
| 661 | } | 748 | } |
| 662 | 749 | ||
| @@ -666,36 +753,50 @@ const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_ty | |||
| 666 | return str; | 753 | return str; |
| 667 | } | 754 | } |
| 668 | 755 | ||
| 669 | double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, | 756 | typedef struct { |
| 670 | mp_dbi_type type) { | 757 | double value; |
| 671 | double val = NAN; | 758 | int error_code; |
| 759 | int dbi_error_code; // not sure if useful | ||
| 760 | } get_field_wrapper; | ||
| 761 | get_field_wrapper get_field(dbi_result res, check_dbi_metric metric, check_dbi_type type) { | ||
| 762 | |||
| 763 | unsigned short field_type = dbi_result_get_field_type_idx(res, 1); | ||
| 764 | get_field_wrapper result = { | ||
| 765 | .value = NAN, | ||
| 766 | .error_code = OK, | ||
| 767 | }; | ||
| 672 | 768 | ||
| 673 | if (*field_type == DBI_TYPE_INTEGER) { | 769 | if (field_type == DBI_TYPE_INTEGER) { |
| 674 | val = (double)dbi_result_get_longlong_idx(res, 1); | 770 | result.value = (double)dbi_result_get_longlong_idx(res, 1); |
| 675 | } else if (*field_type == DBI_TYPE_DECIMAL) { | 771 | } else if (field_type == DBI_TYPE_DECIMAL) { |
| 676 | val = dbi_result_get_double_idx(res, 1); | 772 | result.value = dbi_result_get_double_idx(res, 1); |
| 677 | } else if (*field_type == DBI_TYPE_STRING) { | 773 | } else if (field_type == DBI_TYPE_STRING) { |
| 678 | const char *val_str; | 774 | const char *val_str; |
| 679 | char *endptr = NULL; | 775 | char *endptr = NULL; |
| 680 | 776 | ||
| 681 | val_str = get_field_str(conn, res, *field_type, metric, type); | 777 | val_str = get_field_str(res, metric, type); |
| 682 | if (!val_str) { | 778 | if (!val_str) { |
| 683 | if (metric != METRIC_QUERY_RESULT) { | 779 | result.error_code = ERROR; |
| 684 | return NAN; | 780 | field_type = DBI_TYPE_ERROR; |
| 685 | } | 781 | return result; |
| 686 | *field_type = DBI_TYPE_ERROR; | ||
| 687 | return NAN; | ||
| 688 | } | 782 | } |
| 689 | 783 | ||
| 690 | val = strtod(val_str, &endptr); | 784 | result.value = strtod(val_str, &endptr); |
| 691 | if (endptr == val_str) { | 785 | if (endptr == val_str) { |
| 692 | if (metric != METRIC_QUERY_RESULT) { | 786 | if (metric != METRIC_QUERY_RESULT) { |
| 693 | return NAN; | 787 | result.error_code = ERROR; |
| 788 | return result; | ||
| 694 | } | 789 | } |
| 695 | printf("CRITICAL - result value is not a numeric: %s\n", val_str); | 790 | |
| 696 | *field_type = DBI_TYPE_ERROR; | 791 | if (verbose) { |
| 697 | return NAN; | 792 | printf("CRITICAL - result value is not a numeric: %s\n", val_str); |
| 793 | } | ||
| 794 | |||
| 795 | field_type = DBI_TYPE_ERROR; | ||
| 796 | result.error_code = ERROR; | ||
| 797 | return result; | ||
| 698 | } | 798 | } |
| 799 | |||
| 699 | if ((endptr != NULL) && (*endptr != '\0')) { | 800 | if ((endptr != NULL) && (*endptr != '\0')) { |
| 700 | if (verbose) { | 801 | if (verbose) { |
| 701 | printf("Garbage after value: %s\n", endptr); | 802 | printf("Garbage after value: %s\n", endptr); |
| @@ -703,123 +804,127 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_d | |||
| 703 | } | 804 | } |
| 704 | } else { | 805 | } else { |
| 705 | if (metric != METRIC_QUERY_RESULT) { | 806 | if (metric != METRIC_QUERY_RESULT) { |
| 706 | return NAN; | 807 | result.error_code = ERROR; |
| 808 | return result; | ||
| 707 | } | 809 | } |
| 708 | printf("CRITICAL - cannot parse value of type %s (%i)\n", | 810 | // printf("CRITICAL - cannot parse value of type %s (%i)\n", |
| 709 | (*field_type == DBI_TYPE_BINARY) ? "BINARY" | 811 | // (*field_type == DBI_TYPE_BINARY) ? "BINARY" |
| 710 | : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME" | 812 | // : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME" |
| 711 | : "<unknown>", | 813 | // : "<unknown>", |
| 712 | *field_type); | 814 | // *field_type); |
| 713 | *field_type = DBI_TYPE_ERROR; | 815 | field_type = DBI_TYPE_ERROR; |
| 714 | return NAN; | 816 | result.error_code = ERROR; |
| 715 | } | 817 | } |
| 716 | return val; | 818 | return result; |
| 717 | } | 819 | } |
| 718 | 820 | ||
| 719 | mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, | 821 | static do_query_result do_query(dbi_conn conn, check_dbi_metric metric, check_dbi_type type, |
| 720 | double *res_val, mp_dbi_metric metric, mp_dbi_type type) { | 822 | char *query) { |
| 721 | unsigned short field_type; | 823 | assert(query); |
| 722 | double val = NAN; | ||
| 723 | |||
| 724 | if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) { | ||
| 725 | if (metric != METRIC_QUERY_RESULT) { | ||
| 726 | return STATE_OK; | ||
| 727 | } | ||
| 728 | np_dbi_print_error(conn, "CRITICAL - failed to fetch rows"); | ||
| 729 | return STATE_CRITICAL; | ||
| 730 | } | ||
| 731 | 824 | ||
| 732 | if (dbi_result_get_numrows(res) < 1) { | 825 | if (verbose) { |
| 733 | if (metric != METRIC_QUERY_RESULT) { | 826 | printf("Executing query '%s'\n", query); |
| 734 | return STATE_OK; | ||
| 735 | } | ||
| 736 | printf("WARNING - no rows returned\n"); | ||
| 737 | return STATE_WARNING; | ||
| 738 | } | ||
| 739 | |||
| 740 | if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) { | ||
| 741 | if (metric != METRIC_QUERY_RESULT) { | ||
| 742 | return STATE_OK; | ||
| 743 | } | ||
| 744 | np_dbi_print_error(conn, "CRITICAL - failed to fetch fields"); | ||
| 745 | return STATE_CRITICAL; | ||
| 746 | } | ||
| 747 | |||
| 748 | if (dbi_result_get_numfields(res) < 1) { | ||
| 749 | if (metric != METRIC_QUERY_RESULT) { | ||
| 750 | return STATE_OK; | ||
| 751 | } | ||
| 752 | printf("WARNING - no fields returned\n"); | ||
| 753 | return STATE_WARNING; | ||
| 754 | } | ||
| 755 | |||
| 756 | if (dbi_result_first_row(res) != 1) { | ||
| 757 | if (metric != METRIC_QUERY_RESULT) { | ||
| 758 | return STATE_OK; | ||
| 759 | } | ||
| 760 | np_dbi_print_error(conn, "CRITICAL - failed to fetch first row"); | ||
| 761 | return STATE_CRITICAL; | ||
| 762 | } | 827 | } |
| 763 | 828 | ||
| 764 | field_type = dbi_result_get_field_type_idx(res, 1); | 829 | do_query_result result = { |
| 765 | if (field_type != DBI_TYPE_ERROR) { | 830 | .query_duration = 0, |
| 766 | if (type == TYPE_STRING) { | 831 | .result_string = NULL, |
| 767 | /* the value will be freed in dbi_result_free */ | 832 | .result_number = 0, |
| 768 | *res_val_str = strdup(get_field_str(conn, res, field_type, metric, type)); | 833 | .error_code = 0, |
| 769 | } else { | 834 | .query_processing_status = STATE_UNKNOWN, |
| 770 | val = get_field(conn, res, &field_type, metric, type); | 835 | }; |
| 771 | } | ||
| 772 | } | ||
| 773 | 836 | ||
| 774 | *res_val = val; | 837 | struct timeval timeval_start; |
| 838 | gettimeofday(&timeval_start, NULL); | ||
| 775 | 839 | ||
| 776 | if (field_type == DBI_TYPE_ERROR) { | 840 | dbi_result res = dbi_conn_query(conn, query); |
| 777 | if (metric != METRIC_QUERY_RESULT) { | 841 | if (!res) { |
| 778 | return STATE_OK; | 842 | dbi_conn_error(conn, &result.error_string); |
| 779 | } | 843 | result.error_code = 1; |
| 780 | np_dbi_print_error(conn, "CRITICAL - failed to fetch data"); | 844 | return result; |
| 781 | return STATE_CRITICAL; | ||
| 782 | } | 845 | } |
| 783 | 846 | ||
| 784 | dbi_result_free(res); | ||
| 785 | return STATE_OK; | ||
| 786 | } | ||
| 787 | |||
| 788 | mp_state_enum do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time, | ||
| 789 | mp_dbi_metric metric, mp_dbi_type type, char *np_dbi_query) { | ||
| 790 | dbi_result res; | ||
| 791 | |||
| 792 | struct timeval timeval_start; | ||
| 793 | struct timeval timeval_end; | 847 | struct timeval timeval_end; |
| 794 | mp_state_enum status = STATE_OK; | 848 | gettimeofday(&timeval_end, NULL); |
| 795 | 849 | result.query_duration = timediff(timeval_start, timeval_end); | |
| 796 | assert(np_dbi_query); | ||
| 797 | 850 | ||
| 798 | if (verbose) { | 851 | if (verbose) { |
| 799 | printf("Executing query '%s'\n", np_dbi_query); | 852 | printf("Query duration: %f\n", result.query_duration); |
| 800 | } | 853 | } |
| 801 | 854 | ||
| 802 | gettimeofday(&timeval_start, NULL); | 855 | // Default state is OK, all error will be set explicitly |
| 856 | mp_state_enum query_processing_state = STATE_OK; | ||
| 857 | { | ||
| 803 | 858 | ||
| 804 | res = dbi_conn_query(conn, np_dbi_query); | 859 | if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) { |
| 805 | if (!res) { | 860 | if (metric != METRIC_QUERY_RESULT) { |
| 806 | np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); | 861 | query_processing_state = STATE_OK; |
| 807 | return STATE_CRITICAL; | 862 | } else { |
| 863 | dbi_conn_error(conn, &result.error_string); | ||
| 864 | query_processing_state = STATE_CRITICAL; | ||
| 865 | } | ||
| 866 | } else if (dbi_result_get_numrows(res) < 1) { | ||
| 867 | if (metric != METRIC_QUERY_RESULT) { | ||
| 868 | query_processing_state = STATE_OK; | ||
| 869 | } else { | ||
| 870 | result.error_string = "no rows returned"; | ||
| 871 | // printf("WARNING - no rows returned\n"); | ||
| 872 | query_processing_state = STATE_WARNING; | ||
| 873 | } | ||
| 874 | } else if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) { | ||
| 875 | if (metric != METRIC_QUERY_RESULT) { | ||
| 876 | query_processing_state = STATE_OK; | ||
| 877 | } else { | ||
| 878 | dbi_conn_error(conn, &result.error_string); | ||
| 879 | // np_dbi_print_error(conn, "CRITICAL - failed to fetch fields"); | ||
| 880 | query_processing_state = STATE_CRITICAL; | ||
| 881 | } | ||
| 882 | } else if (dbi_result_get_numfields(res) < 1) { | ||
| 883 | if (metric != METRIC_QUERY_RESULT) { | ||
| 884 | query_processing_state = STATE_OK; | ||
| 885 | } else { | ||
| 886 | result.error_string = "no fields returned"; | ||
| 887 | // printf("WARNING - no fields returned\n"); | ||
| 888 | query_processing_state = STATE_WARNING; | ||
| 889 | } | ||
| 890 | } else if (dbi_result_first_row(res) != 1) { | ||
| 891 | if (metric != METRIC_QUERY_RESULT) { | ||
| 892 | query_processing_state = STATE_OK; | ||
| 893 | } else { | ||
| 894 | dbi_conn_error(conn, &result.error_string); | ||
| 895 | // np_dbi_print_error(conn, "CRITICAL - failed to fetch first row"); | ||
| 896 | query_processing_state = STATE_CRITICAL; | ||
| 897 | } | ||
| 898 | } else { | ||
| 899 | unsigned short field_type = dbi_result_get_field_type_idx(res, 1); | ||
| 900 | if (field_type != DBI_TYPE_ERROR) { | ||
| 901 | if (type == TYPE_STRING) { | ||
| 902 | result.result_string = strdup(get_field_str(res, metric, type)); | ||
| 903 | } else { | ||
| 904 | get_field_wrapper gfw = get_field(res, metric, type); | ||
| 905 | result.result_number = gfw.value; | ||
| 906 | } | ||
| 907 | } else { | ||
| 908 | // Error when retrieving the field, that is OK if the Query result is not of | ||
| 909 | // interest | ||
| 910 | if (metric != METRIC_QUERY_RESULT) { | ||
| 911 | query_processing_state = STATE_OK; | ||
| 912 | } else { | ||
| 913 | dbi_conn_error(conn, &result.error_string); | ||
| 914 | // np_dbi_print_error(conn, "CRITICAL - failed to fetch data"); | ||
| 915 | query_processing_state = STATE_CRITICAL; | ||
| 916 | } | ||
| 917 | } | ||
| 918 | } | ||
| 808 | } | 919 | } |
| 920 | dbi_result_free(res); | ||
| 809 | 921 | ||
| 810 | status = get_query_result(conn, res, res_val_str, res_val, metric, type); | 922 | result.query_processing_status = query_processing_state; |
| 811 | |||
| 812 | gettimeofday(&timeval_end, NULL); | ||
| 813 | *res_time = timediff(timeval_start, timeval_end); | ||
| 814 | |||
| 815 | if (verbose) { | ||
| 816 | printf("Time elapsed: %f\n", *res_time); | ||
| 817 | } | ||
| 818 | 923 | ||
| 819 | return status; | 924 | return result; |
| 820 | } | 925 | } |
| 821 | 926 | ||
| 822 | double timediff(struct timeval start, struct timeval end) { | 927 | static double timediff(struct timeval start, struct timeval end) { |
| 823 | double diff; | 928 | double diff; |
| 824 | 929 | ||
| 825 | while (start.tv_usec > end.tv_usec) { | 930 | while (start.tv_usec > end.tv_usec) { |
| @@ -830,7 +935,7 @@ double timediff(struct timeval start, struct timeval end) { | |||
| 830 | return diff; | 935 | return diff; |
| 831 | } | 936 | } |
| 832 | 937 | ||
| 833 | void np_dbi_print_error(dbi_conn conn, char *fmt, ...) { | 938 | static void np_dbi_print_error(dbi_conn conn, char *fmt, ...) { |
| 834 | const char *errmsg = NULL; | 939 | const char *errmsg = NULL; |
| 835 | va_list ap; | 940 | va_list ap; |
| 836 | 941 | ||
diff --git a/plugins/check_dbi.d/config.h b/plugins/check_dbi.d/config.h index f6f0d7b3..25d74a12 100644 --- a/plugins/check_dbi.d/config.h +++ b/plugins/check_dbi.d/config.h | |||
| @@ -3,18 +3,19 @@ | |||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include <stddef.h> | 4 | #include <stddef.h> |
| 5 | #include "../../lib/monitoringplug.h" | 5 | #include "../../lib/monitoringplug.h" |
| 6 | #include "thresholds.h" | ||
| 6 | 7 | ||
| 7 | typedef enum { | 8 | typedef enum { |
| 8 | METRIC_CONN_TIME, | 9 | METRIC_CONN_TIME, |
| 9 | METRIC_SERVER_VERSION, | 10 | METRIC_SERVER_VERSION, |
| 10 | METRIC_QUERY_RESULT, | 11 | METRIC_QUERY_RESULT, |
| 11 | METRIC_QUERY_TIME, | 12 | METRIC_QUERY_TIME, |
| 12 | } mp_dbi_metric; | 13 | } check_dbi_metric; |
| 13 | 14 | ||
| 14 | typedef enum { | 15 | typedef enum { |
| 15 | TYPE_NUMERIC, | 16 | TYPE_NUMERIC, |
| 16 | TYPE_STRING, | 17 | TYPE_STRING, |
| 17 | } mp_dbi_type; | 18 | } check_dbi_type; |
| 18 | 19 | ||
| 19 | typedef struct { | 20 | typedef struct { |
| 20 | char *key; | 21 | char *key; |
| @@ -24,20 +25,22 @@ typedef struct { | |||
| 24 | typedef struct { | 25 | typedef struct { |
| 25 | char *dbi_driver; | 26 | char *dbi_driver; |
| 26 | char *host; | 27 | char *host; |
| 28 | |||
| 27 | driver_option_t *dbi_options; | 29 | driver_option_t *dbi_options; |
| 28 | size_t dbi_options_num; | 30 | size_t dbi_options_num; |
| 29 | char *dbi_database; | 31 | |
| 30 | char *dbi_query; | 32 | char *database; |
| 33 | char *query; | ||
| 31 | 34 | ||
| 32 | char *expect; | 35 | char *expect; |
| 33 | char *expect_re_str; | 36 | char *expect_re_str; |
| 34 | int expect_re_cflags; | 37 | int expect_re_cflags; |
| 35 | mp_dbi_metric metric; | 38 | check_dbi_metric metric; |
| 36 | mp_dbi_type type; | 39 | check_dbi_type type; |
| 37 | char *warning_range; | 40 | mp_thresholds thresholds; |
| 38 | char *critical_range; | ||
| 39 | thresholds *dbi_thresholds; | ||
| 40 | 41 | ||
| 42 | bool output_format_is_set; | ||
| 43 | mp_output_format output_format; | ||
| 41 | } check_dbi_config; | 44 | } check_dbi_config; |
| 42 | 45 | ||
| 43 | check_dbi_config check_dbi_config_init() { | 46 | check_dbi_config check_dbi_config_init() { |
| @@ -46,8 +49,8 @@ check_dbi_config check_dbi_config_init() { | |||
| 46 | .host = NULL, | 49 | .host = NULL, |
| 47 | .dbi_options = NULL, | 50 | .dbi_options = NULL, |
| 48 | .dbi_options_num = 0, | 51 | .dbi_options_num = 0, |
| 49 | .dbi_database = NULL, | 52 | .database = NULL, |
| 50 | .dbi_query = NULL, | 53 | .query = NULL, |
| 51 | 54 | ||
| 52 | .expect = NULL, | 55 | .expect = NULL, |
| 53 | .expect_re_str = NULL, | 56 | .expect_re_str = NULL, |
| @@ -55,9 +58,9 @@ check_dbi_config check_dbi_config_init() { | |||
| 55 | .metric = METRIC_QUERY_RESULT, | 58 | .metric = METRIC_QUERY_RESULT, |
| 56 | .type = TYPE_NUMERIC, | 59 | .type = TYPE_NUMERIC, |
| 57 | 60 | ||
| 58 | .warning_range = NULL, | 61 | .thresholds = mp_thresholds_init(), |
| 59 | .critical_range = NULL, | 62 | |
| 60 | .dbi_thresholds = NULL, | 63 | .output_format_is_set = false, |
| 61 | }; | 64 | }; |
| 62 | return tmp; | 65 | return tmp; |
| 63 | } | 66 | } |
diff --git a/plugins/check_ldap.c b/plugins/check_ldap.c index 77a33304..1b2e2826 100644 --- a/plugins/check_ldap.c +++ b/plugins/check_ldap.c | |||
| @@ -27,12 +27,11 @@ | |||
| 27 | *****************************************************************************/ | 27 | *****************************************************************************/ |
| 28 | 28 | ||
| 29 | /* progname may be check_ldaps */ | 29 | /* progname may be check_ldaps */ |
| 30 | char *progname = "check_ldap"; | 30 | #include "output.h" |
| 31 | const char *copyright = "2000-2024"; | ||
| 32 | const char *email = "devel@monitoring-plugins.org"; | ||
| 33 | |||
| 34 | #include "common.h" | 31 | #include "common.h" |
| 35 | #include "netutils.h" | 32 | #include "netutils.h" |
| 33 | #include "perfdata.h" | ||
| 34 | #include "thresholds.h" | ||
| 36 | #include "utils.h" | 35 | #include "utils.h" |
| 37 | #include "check_ldap.d/config.h" | 36 | #include "check_ldap.d/config.h" |
| 38 | 37 | ||
| @@ -41,6 +40,10 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 41 | #define LDAP_DEPRECATED 1 | 40 | #define LDAP_DEPRECATED 1 |
| 42 | #include <ldap.h> | 41 | #include <ldap.h> |
| 43 | 42 | ||
| 43 | char *progname = "check_ldap"; | ||
| 44 | const char *copyright = "2000-2024"; | ||
| 45 | const char *email = "devel@monitoring-plugins.org"; | ||
| 46 | |||
| 44 | enum { | 47 | enum { |
| 45 | DEFAULT_PORT = 389 | 48 | DEFAULT_PORT = 389 |
| 46 | }; | 49 | }; |
| @@ -79,6 +82,10 @@ int main(int argc, char *argv[]) { | |||
| 79 | 82 | ||
| 80 | const check_ldap_config config = tmp_config.config; | 83 | const check_ldap_config config = tmp_config.config; |
| 81 | 84 | ||
| 85 | if (config.output_format_is_set) { | ||
| 86 | mp_set_format(config.output_format); | ||
| 87 | } | ||
| 88 | |||
| 82 | /* initialize alarm signal handling */ | 89 | /* initialize alarm signal handling */ |
| 83 | signal(SIGALRM, socket_timeout_alarm_handler); | 90 | signal(SIGALRM, socket_timeout_alarm_handler); |
| 84 | 91 | ||
| @@ -89,101 +96,172 @@ int main(int argc, char *argv[]) { | |||
| 89 | struct timeval start_time; | 96 | struct timeval start_time; |
| 90 | gettimeofday(&start_time, NULL); | 97 | gettimeofday(&start_time, NULL); |
| 91 | 98 | ||
| 99 | mp_check overall = mp_check_init(); | ||
| 100 | |||
| 92 | LDAP *ldap_connection; | 101 | LDAP *ldap_connection; |
| 93 | /* initialize ldap */ | 102 | /* initialize ldap */ |
| 103 | { | ||
| 94 | #ifdef HAVE_LDAP_INIT | 104 | #ifdef HAVE_LDAP_INIT |
| 95 | if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) { | 105 | mp_subcheck sc_ldap_init = mp_subcheck_init(); |
| 96 | printf("Could not connect to the server at port %i\n", config.ld_port); | 106 | if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) { |
| 97 | return STATE_CRITICAL; | 107 | xasprintf(&sc_ldap_init.output, "could not connect to the server at port %i", |
| 98 | } | 108 | config.ld_port); |
| 109 | sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_CRITICAL); | ||
| 110 | mp_add_subcheck_to_check(&overall, sc_ldap_init); | ||
| 111 | mp_exit(overall); | ||
| 112 | } else { | ||
| 113 | xasprintf(&sc_ldap_init.output, "connected to the server at port %i", config.ld_port); | ||
| 114 | sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_OK); | ||
| 115 | mp_add_subcheck_to_check(&overall, sc_ldap_init); | ||
| 116 | } | ||
| 99 | #else | 117 | #else |
| 100 | if (!(ld = ldap_open(config.ld_host, config.ld_port))) { | 118 | mp_subcheck sc_ldap_init = mp_subcheck_init(); |
| 101 | if (verbose) { | 119 | if (!(ld = ldap_open(config.ld_host, config.ld_port))) { |
| 102 | ldap_perror(ldap_connection, "ldap_open"); | 120 | if (verbose) { |
| 121 | ldap_perror(ldap_connection, "ldap_open"); | ||
| 122 | } | ||
| 123 | xasprintf(&sc_ldap_init.output, "Could not connect to the server at port %i"), config.ld_port); | ||
| 124 | sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_CRITICAL); | ||
| 125 | mp_add_subcheck_to_check(&overall, sc_ldap_init); | ||
| 126 | mp_exit(overall); | ||
| 127 | } else { | ||
| 128 | xasprintf(&sc_ldap_init.output, "connected to the server at port %i", config.ld_port); | ||
| 129 | sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_OK); | ||
| 130 | mp_add_subcheck_to_check(&overall, sc_ldap_init); | ||
| 103 | } | 131 | } |
| 104 | printf(_("Could not connect to the server at port %i\n"), config.ld_port); | ||
| 105 | return STATE_CRITICAL; | ||
| 106 | } | ||
| 107 | #endif /* HAVE_LDAP_INIT */ | 132 | #endif /* HAVE_LDAP_INIT */ |
| 133 | } | ||
| 108 | 134 | ||
| 109 | #ifdef HAVE_LDAP_SET_OPTION | 135 | #ifdef HAVE_LDAP_SET_OPTION |
| 110 | /* set ldap options */ | 136 | /* set ldap options */ |
| 137 | mp_subcheck sc_ldap_set_opts = mp_subcheck_init(); | ||
| 111 | if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != | 138 | if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != |
| 112 | LDAP_OPT_SUCCESS) { | 139 | LDAP_OPT_SUCCESS) { |
| 113 | printf(_("Could not set protocol version %d\n"), config.ld_protocol); | 140 | xasprintf(&sc_ldap_set_opts.output, "Could not set protocol version %d", |
| 114 | return STATE_CRITICAL; | 141 | config.ld_protocol); |
| 142 | sc_ldap_set_opts = mp_set_subcheck_state(sc_ldap_set_opts, STATE_CRITICAL); | ||
| 143 | mp_add_subcheck_to_check(&overall, sc_ldap_set_opts); | ||
| 144 | mp_exit(overall); | ||
| 145 | } else { | ||
| 146 | xasprintf(&sc_ldap_set_opts.output, "set protocol version %d", config.ld_protocol); | ||
| 147 | sc_ldap_set_opts = mp_set_subcheck_state(sc_ldap_set_opts, STATE_OK); | ||
| 148 | mp_add_subcheck_to_check(&overall, sc_ldap_set_opts); | ||
| 115 | } | 149 | } |
| 116 | #endif | 150 | #endif |
| 117 | 151 | ||
| 118 | int version = 3; | 152 | int version = 3; |
| 119 | int tls; | 153 | int tls; |
| 120 | if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) { | 154 | { |
| 155 | if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) { | ||
| 121 | #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) | 156 | #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) |
| 122 | /* ldaps: set option tls */ | 157 | /* ldaps: set option tls */ |
| 123 | tls = LDAP_OPT_X_TLS_HARD; | 158 | tls = LDAP_OPT_X_TLS_HARD; |
| 124 | 159 | ||
| 125 | if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { | 160 | mp_subcheck sc_ldap_tls_init = mp_subcheck_init(); |
| 126 | if (verbose) { | 161 | if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { |
| 127 | ldap_perror(ldap_connection, "ldaps_option"); | 162 | if (verbose) { |
| 163 | ldap_perror(ldap_connection, "ldaps_option"); | ||
| 164 | } | ||
| 165 | xasprintf(&sc_ldap_tls_init.output, "could not init TLS at port %i!", | ||
| 166 | config.ld_port); | ||
| 167 | sc_ldap_tls_init = mp_set_subcheck_state(sc_ldap_tls_init, STATE_CRITICAL); | ||
| 168 | mp_add_subcheck_to_check(&overall, sc_ldap_tls_init); | ||
| 169 | mp_exit(overall); | ||
| 170 | } else { | ||
| 171 | xasprintf(&sc_ldap_tls_init.output, "initiated TLS at port %i!", config.ld_port); | ||
| 172 | sc_ldap_tls_init = mp_set_subcheck_state(sc_ldap_tls_init, STATE_OK); | ||
| 173 | mp_add_subcheck_to_check(&overall, sc_ldap_tls_init); | ||
| 128 | } | 174 | } |
| 129 | printf(_("Could not init TLS at port %i!\n"), config.ld_port); | ||
| 130 | return STATE_CRITICAL; | ||
| 131 | } | ||
| 132 | #else | 175 | #else |
| 133 | printf(_("TLS not supported by the libraries!\n")); | 176 | printf(_("TLS not supported by the libraries!\n")); |
| 134 | return STATE_CRITICAL; | 177 | exit(STATE_CRITICAL); |
| 135 | #endif /* LDAP_OPT_X_TLS */ | 178 | #endif /* LDAP_OPT_X_TLS */ |
| 136 | } else if (config.starttls) { | 179 | } else if (config.starttls) { |
| 137 | #if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) | 180 | #if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) |
| 138 | /* ldap with startTLS: set option version */ | 181 | /* ldap with startTLS: set option version */ |
| 139 | if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == | 182 | if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == |
| 140 | LDAP_OPT_SUCCESS) { | 183 | LDAP_OPT_SUCCESS) { |
| 141 | if (version < LDAP_VERSION3) { | 184 | if (version < LDAP_VERSION3) { |
| 142 | version = LDAP_VERSION3; | 185 | version = LDAP_VERSION3; |
| 143 | ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version); | 186 | ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version); |
| 187 | } | ||
| 144 | } | 188 | } |
| 145 | } | 189 | /* call start_tls */ |
| 146 | /* call start_tls */ | 190 | mp_subcheck sc_ldap_starttls = mp_subcheck_init(); |
| 147 | if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) { | 191 | if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) { |
| 148 | if (verbose) { | 192 | if (verbose) { |
| 149 | ldap_perror(ldap_connection, "ldap_start_tls"); | 193 | ldap_perror(ldap_connection, "ldap_start_tls"); |
| 194 | } | ||
| 195 | xasprintf(&sc_ldap_starttls.output, "could not init STARTTLS at port %i!", | ||
| 196 | config.ld_port); | ||
| 197 | sc_ldap_starttls = mp_set_subcheck_state(sc_ldap_starttls, STATE_CRITICAL); | ||
| 198 | mp_add_subcheck_to_check(&overall, sc_ldap_starttls); | ||
| 199 | mp_exit(overall); | ||
| 200 | } else { | ||
| 201 | xasprintf(&sc_ldap_starttls.output, "initiated STARTTLS at port %i!", | ||
| 202 | config.ld_port); | ||
| 203 | sc_ldap_starttls = mp_set_subcheck_state(sc_ldap_starttls, STATE_OK); | ||
| 204 | mp_add_subcheck_to_check(&overall, sc_ldap_starttls); | ||
| 150 | } | 205 | } |
| 151 | printf(_("Could not init startTLS at port %i!\n"), config.ld_port); | ||
| 152 | return STATE_CRITICAL; | ||
| 153 | } | ||
| 154 | #else | 206 | #else |
| 155 | printf(_("startTLS not supported by the library, needs LDAPv3!\n")); | 207 | printf(_("startTLS not supported by the library, needs LDAPv3!\n")); |
| 156 | return STATE_CRITICAL; | 208 | exit(STATE_CRITICAL); |
| 157 | #endif /* HAVE_LDAP_START_TLS_S */ | 209 | #endif /* HAVE_LDAP_START_TLS_S */ |
| 210 | } | ||
| 158 | } | 211 | } |
| 159 | 212 | ||
| 160 | /* bind to the ldap server */ | 213 | /* bind to the ldap server */ |
| 161 | if (ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE) != | 214 | { |
| 162 | LDAP_SUCCESS) { | 215 | mp_subcheck sc_ldap_bind = mp_subcheck_init(); |
| 163 | if (verbose) { | 216 | int ldap_error = |
| 164 | ldap_perror(ldap_connection, "ldap_bind"); | 217 | ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE); |
| 218 | if (ldap_error != LDAP_SUCCESS) { | ||
| 219 | if (verbose) { | ||
| 220 | ldap_perror(ldap_connection, "ldap_bind"); | ||
| 221 | } | ||
| 222 | |||
| 223 | xasprintf(&sc_ldap_bind.output, "could not bind to the LDAP server: %s", | ||
| 224 | ldap_err2string(ldap_error)); | ||
| 225 | sc_ldap_bind = mp_set_subcheck_state(sc_ldap_bind, STATE_CRITICAL); | ||
| 226 | mp_add_subcheck_to_check(&overall, sc_ldap_bind); | ||
| 227 | mp_exit(overall); | ||
| 228 | } else { | ||
| 229 | xasprintf(&sc_ldap_bind.output, "execute bind to the LDAP server"); | ||
| 230 | sc_ldap_bind = mp_set_subcheck_state(sc_ldap_bind, STATE_OK); | ||
| 231 | mp_add_subcheck_to_check(&overall, sc_ldap_bind); | ||
| 165 | } | 232 | } |
| 166 | printf(_("Could not bind to the LDAP server\n")); | ||
| 167 | return STATE_CRITICAL; | ||
| 168 | } | 233 | } |
| 169 | 234 | ||
| 170 | LDAPMessage *result; | 235 | LDAPMessage *result; |
| 171 | int num_entries = 0; | ||
| 172 | /* do a search of all objectclasses in the base dn */ | 236 | /* do a search of all objectclasses in the base dn */ |
| 173 | if (ldap_search_s(ldap_connection, config.ld_base, | 237 | { |
| 174 | (config.crit_entries != NULL || config.warn_entries != NULL) | 238 | mp_subcheck sc_ldap_search = mp_subcheck_init(); |
| 175 | ? LDAP_SCOPE_SUBTREE | 239 | int ldap_error = ldap_search_s( |
| 176 | : LDAP_SCOPE_BASE, | 240 | ldap_connection, config.ld_base, |
| 177 | config.ld_attr, NULL, 0, &result) != LDAP_SUCCESS) { | 241 | (config.entries_thresholds.warning_is_set || config.entries_thresholds.critical_is_set) |
| 178 | if (verbose) { | 242 | ? LDAP_SCOPE_SUBTREE |
| 179 | ldap_perror(ldap_connection, "ldap_search"); | 243 | : LDAP_SCOPE_BASE, |
| 244 | config.ld_attr, NULL, 0, &result); | ||
| 245 | |||
| 246 | if (ldap_error != LDAP_SUCCESS) { | ||
| 247 | if (verbose) { | ||
| 248 | ldap_perror(ldap_connection, "ldap_search"); | ||
| 249 | } | ||
| 250 | xasprintf(&sc_ldap_search.output, "could not search/find objectclasses in %s: %s", | ||
| 251 | config.ld_base, ldap_err2string(ldap_error)); | ||
| 252 | sc_ldap_search = mp_set_subcheck_state(sc_ldap_search, STATE_CRITICAL); | ||
| 253 | mp_add_subcheck_to_check(&overall, sc_ldap_search); | ||
| 254 | mp_exit(overall); | ||
| 255 | } else { | ||
| 256 | xasprintf(&sc_ldap_search.output, "search/find objectclasses in %s", config.ld_base); | ||
| 257 | sc_ldap_search = mp_set_subcheck_state(sc_ldap_search, STATE_OK); | ||
| 258 | mp_add_subcheck_to_check(&overall, sc_ldap_search); | ||
| 180 | } | 259 | } |
| 181 | printf(_("Could not search/find objectclasses in %s\n"), config.ld_base); | ||
| 182 | return STATE_CRITICAL; | ||
| 183 | } | 260 | } |
| 184 | 261 | ||
| 185 | if (config.crit_entries != NULL || config.warn_entries != NULL) { | 262 | int num_entries = ldap_count_entries(ldap_connection, result); |
| 186 | num_entries = ldap_count_entries(ldap_connection, result); | 263 | if (verbose) { |
| 264 | printf("entries found: %d\n", num_entries); | ||
| 187 | } | 265 | } |
| 188 | 266 | ||
| 189 | /* unbind from the ldap server */ | 267 | /* unbind from the ldap server */ |
| @@ -193,50 +271,50 @@ int main(int argc, char *argv[]) { | |||
| 193 | alarm(0); | 271 | alarm(0); |
| 194 | 272 | ||
| 195 | /* calculate the elapsed time and compare to thresholds */ | 273 | /* calculate the elapsed time and compare to thresholds */ |
| 196 | |||
| 197 | long microsec = deltime(start_time); | 274 | long microsec = deltime(start_time); |
| 198 | double elapsed_time = (double)microsec / 1.0e6; | 275 | double elapsed_time = (double)microsec / 1.0e6; |
| 199 | mp_state_enum status = STATE_UNKNOWN; | 276 | mp_perfdata pd_connection_time = perfdata_init(); |
| 200 | if (config.crit_time_set && elapsed_time > config.crit_time) { | 277 | pd_connection_time.label = "time"; |
| 201 | status = STATE_CRITICAL; | 278 | pd_connection_time.value = mp_create_pd_value(elapsed_time); |
| 202 | } else if (config.warn_time_set && elapsed_time > config.warn_time) { | 279 | pd_connection_time = mp_pd_set_thresholds(pd_connection_time, config.connection_time_threshold); |
| 203 | status = STATE_WARNING; | ||
| 204 | } else { | ||
| 205 | status = STATE_OK; | ||
| 206 | } | ||
| 207 | 280 | ||
| 208 | if (config.entries_thresholds != NULL) { | 281 | mp_subcheck sc_connection_time = mp_subcheck_init(); |
| 209 | if (verbose) { | 282 | mp_add_perfdata_to_subcheck(&sc_connection_time, pd_connection_time); |
| 210 | printf("entries found: %d\n", num_entries); | 283 | |
| 211 | print_thresholds("entry thresholds", config.entries_thresholds); | 284 | mp_state_enum connection_time_state = mp_get_pd_status(pd_connection_time); |
| 212 | } | 285 | sc_connection_time = mp_set_subcheck_state(sc_connection_time, connection_time_state); |
| 213 | mp_state_enum status_entries = get_status(num_entries, config.entries_thresholds); | ||
| 214 | if (status_entries == STATE_CRITICAL) { | ||
| 215 | status = STATE_CRITICAL; | ||
| 216 | } else if (status != STATE_CRITICAL) { | ||
| 217 | status = status_entries; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | 286 | ||
| 221 | /* print out the result */ | 287 | if (connection_time_state == STATE_OK) { |
| 222 | if (config.crit_entries != NULL || config.warn_entries != NULL) { | 288 | xasprintf(&sc_connection_time.output, "connection time %.3fs is within thresholds", |
| 223 | printf(_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), state_text(status), | 289 | elapsed_time); |
| 224 | num_entries, elapsed_time, | ||
| 225 | fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, | ||
| 226 | config.crit_time_set, config.crit_time, true, 0, false, 0), | ||
| 227 | sperfdata("entries", (double)num_entries, "", config.warn_entries, | ||
| 228 | config.crit_entries, true, 0.0, false, 0.0)); | ||
| 229 | } else { | 290 | } else { |
| 230 | printf(_("LDAP %s - %.3f seconds response time|%s\n"), state_text(status), elapsed_time, | 291 | xasprintf(&sc_connection_time.output, "connection time %.3fs is violating thresholds", |
| 231 | fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, | 292 | elapsed_time); |
| 232 | config.crit_time_set, config.crit_time, true, 0, false, 0)); | ||
| 233 | } | 293 | } |
| 234 | 294 | ||
| 235 | exit(status); | 295 | mp_add_subcheck_to_check(&overall, sc_connection_time); |
| 296 | |||
| 297 | mp_perfdata pd_num_entries = perfdata_init(); | ||
| 298 | pd_num_entries.label = "entries"; | ||
| 299 | pd_num_entries.value = mp_create_pd_value(num_entries); | ||
| 300 | pd_num_entries = mp_pd_set_thresholds(pd_num_entries, config.entries_thresholds); | ||
| 301 | |||
| 302 | mp_subcheck sc_num_entries = mp_subcheck_init(); | ||
| 303 | mp_add_perfdata_to_subcheck(&sc_num_entries, pd_num_entries); | ||
| 304 | xasprintf(&sc_num_entries.output, "found %d entries", num_entries); | ||
| 305 | sc_num_entries = mp_set_subcheck_state(sc_num_entries, mp_get_pd_status(pd_num_entries)); | ||
| 306 | |||
| 307 | mp_add_subcheck_to_check(&overall, sc_num_entries); | ||
| 308 | |||
| 309 | mp_exit(overall); | ||
| 236 | } | 310 | } |
| 237 | 311 | ||
| 238 | /* process command-line arguments */ | 312 | /* process command-line arguments */ |
| 239 | check_ldap_config_wrapper process_arguments(int argc, char **argv) { | 313 | check_ldap_config_wrapper process_arguments(int argc, char **argv) { |
| 314 | enum { | ||
| 315 | output_format_index = CHAR_MAX + 1, | ||
| 316 | }; | ||
| 317 | |||
| 240 | /* initialize the long option struct */ | 318 | /* initialize the long option struct */ |
| 241 | static struct option longopts[] = {{"help", no_argument, 0, 'h'}, | 319 | static struct option longopts[] = {{"help", no_argument, 0, 'h'}, |
| 242 | {"version", no_argument, 0, 'V'}, | 320 | {"version", no_argument, 0, 'V'}, |
| @@ -260,6 +338,7 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) { | |||
| 260 | {"warn-entries", required_argument, 0, 'W'}, | 338 | {"warn-entries", required_argument, 0, 'W'}, |
| 261 | {"crit-entries", required_argument, 0, 'C'}, | 339 | {"crit-entries", required_argument, 0, 'C'}, |
| 262 | {"verbose", no_argument, 0, 'v'}, | 340 | {"verbose", no_argument, 0, 'v'}, |
| 341 | {"output-format", required_argument, 0, output_format_index}, | ||
| 263 | {0, 0, 0, 0}}; | 342 | {0, 0, 0, 0}}; |
| 264 | 343 | ||
| 265 | check_ldap_config_wrapper result = { | 344 | check_ldap_config_wrapper result = { |
| @@ -319,20 +398,38 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) { | |||
| 319 | case 'P': | 398 | case 'P': |
| 320 | result.config.ld_passwd = optarg; | 399 | result.config.ld_passwd = optarg; |
| 321 | break; | 400 | break; |
| 322 | case 'w': | 401 | case 'w': { |
| 323 | result.config.warn_time_set = true; | 402 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 324 | result.config.warn_time = strtod(optarg, NULL); | 403 | if (tmp.error != MP_PARSING_SUCCES) { |
| 325 | break; | 404 | die(STATE_UNKNOWN, "failed to parse warning connection time threshold"); |
| 326 | case 'c': | 405 | } |
| 327 | result.config.crit_time_set = true; | 406 | result.config.connection_time_threshold = |
| 328 | result.config.crit_time = strtod(optarg, NULL); | 407 | mp_thresholds_set_warn(result.config.connection_time_threshold, tmp.range); |
| 329 | break; | 408 | } break; |
| 330 | case 'W': | 409 | case 'c': { |
| 331 | result.config.warn_entries = optarg; | 410 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 332 | break; | 411 | if (tmp.error != MP_PARSING_SUCCES) { |
| 333 | case 'C': | 412 | die(STATE_UNKNOWN, "failed to parse critical connection time threshold"); |
| 334 | result.config.crit_entries = optarg; | 413 | } |
| 335 | break; | 414 | result.config.connection_time_threshold = |
| 415 | mp_thresholds_set_crit(result.config.connection_time_threshold, tmp.range); | ||
| 416 | } break; | ||
| 417 | case 'W': { | ||
| 418 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 419 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 420 | die(STATE_UNKNOWN, "failed to parse number of entries warning threshold"); | ||
| 421 | } | ||
| 422 | result.config.entries_thresholds = | ||
| 423 | mp_thresholds_set_warn(result.config.entries_thresholds, tmp.range); | ||
| 424 | } break; | ||
| 425 | case 'C': { | ||
| 426 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 427 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 428 | die(STATE_UNKNOWN, "failed to parse number of entries critical threshold"); | ||
| 429 | } | ||
| 430 | result.config.entries_thresholds = | ||
| 431 | mp_thresholds_set_crit(result.config.entries_thresholds, tmp.range); | ||
| 432 | } break; | ||
| 336 | #ifdef HAVE_LDAP_SET_OPTION | 433 | #ifdef HAVE_LDAP_SET_OPTION |
| 337 | case '2': | 434 | case '2': |
| 338 | result.config.ld_protocol = 2; | 435 | result.config.ld_protocol = 2; |
| @@ -371,6 +468,18 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) { | |||
| 371 | usage(_("IPv6 support not available\n")); | 468 | usage(_("IPv6 support not available\n")); |
| 372 | #endif | 469 | #endif |
| 373 | break; | 470 | break; |
| 471 | case output_format_index: { | ||
| 472 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 473 | if (!parser.parsing_success) { | ||
| 474 | // TODO List all available formats here, maybe add anothoer usage function | ||
| 475 | printf("Invalid output format: %s\n", optarg); | ||
| 476 | exit(STATE_UNKNOWN); | ||
| 477 | } | ||
| 478 | |||
| 479 | result.config.output_format_is_set = true; | ||
| 480 | result.config.output_format = parser.output_format; | ||
| 481 | break; | ||
| 482 | } | ||
| 374 | default: | 483 | default: |
| 375 | usage5(); | 484 | usage5(); |
| 376 | } | 485 | } |
| @@ -406,11 +515,6 @@ check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper config_wr | |||
| 406 | usage4(_("Please specify the LDAP base\n")); | 515 | usage4(_("Please specify the LDAP base\n")); |
| 407 | } | 516 | } |
| 408 | 517 | ||
| 409 | if (config_wrapper.config.crit_entries != NULL || config_wrapper.config.warn_entries != NULL) { | ||
| 410 | set_thresholds(&config_wrapper.config.entries_thresholds, | ||
| 411 | config_wrapper.config.warn_entries, config_wrapper.config.crit_entries); | ||
| 412 | } | ||
| 413 | |||
| 414 | if (config_wrapper.config.ld_passwd == NULL) { | 518 | if (config_wrapper.config.ld_passwd == NULL) { |
| 415 | config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD"); | 519 | config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD"); |
| 416 | } | 520 | } |
| @@ -471,6 +575,7 @@ void print_help(void) { | |||
| 471 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 575 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
| 472 | 576 | ||
| 473 | printf(UT_VERBOSE); | 577 | printf(UT_VERBOSE); |
| 578 | printf(UT_OUTPUT_FORMAT); | ||
| 474 | 579 | ||
| 475 | printf("\n"); | 580 | printf("\n"); |
| 476 | printf("%s\n", _("Notes:")); | 581 | printf("%s\n", _("Notes:")); |
diff --git a/plugins/check_ldap.d/config.h b/plugins/check_ldap.d/config.h index c8a40610..50191725 100644 --- a/plugins/check_ldap.d/config.h +++ b/plugins/check_ldap.d/config.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 4 | #include "thresholds.h" | 5 | #include "thresholds.h" |
| 5 | #include <stddef.h> | 6 | #include <stddef.h> |
| 6 | 7 | ||
| @@ -25,13 +26,11 @@ typedef struct { | |||
| 25 | int ld_protocol; | 26 | int ld_protocol; |
| 26 | #endif | 27 | #endif |
| 27 | 28 | ||
| 28 | char *warn_entries; | 29 | mp_thresholds entries_thresholds; |
| 29 | char *crit_entries; | 30 | mp_thresholds connection_time_threshold; |
| 30 | thresholds *entries_thresholds; | 31 | |
| 31 | bool warn_time_set; | 32 | bool output_format_is_set; |
| 32 | double warn_time; | 33 | mp_output_format output_format; |
| 33 | bool crit_time_set; | ||
| 34 | double crit_time; | ||
| 35 | } check_ldap_config; | 34 | } check_ldap_config; |
| 36 | 35 | ||
| 37 | check_ldap_config check_ldap_config_init() { | 36 | check_ldap_config check_ldap_config_init() { |
| @@ -48,13 +47,10 @@ check_ldap_config check_ldap_config_init() { | |||
| 48 | .ld_protocol = DEFAULT_PROTOCOL, | 47 | .ld_protocol = DEFAULT_PROTOCOL, |
| 49 | #endif | 48 | #endif |
| 50 | 49 | ||
| 51 | .warn_entries = NULL, | 50 | .entries_thresholds = mp_thresholds_init(), |
| 52 | .crit_entries = NULL, | 51 | .connection_time_threshold = mp_thresholds_init(), |
| 53 | .entries_thresholds = NULL, | 52 | |
| 54 | .warn_time_set = false, | 53 | .output_format_is_set = false, |
| 55 | .warn_time = 0, | ||
| 56 | .crit_time_set = false, | ||
| 57 | .crit_time = 0, | ||
| 58 | }; | 54 | }; |
| 59 | return tmp; | 55 | return tmp; |
| 60 | } | 56 | } |
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c index 6134d6c6..9d8094c0 100644 --- a/plugins/check_mysql.c +++ b/plugins/check_mysql.c | |||
| @@ -30,13 +30,11 @@ | |||
| 30 | * | 30 | * |
| 31 | *****************************************************************************/ | 31 | *****************************************************************************/ |
| 32 | 32 | ||
| 33 | const char *progname = "check_mysql"; | ||
| 34 | const char *copyright = "1999-2024"; | ||
| 35 | const char *email = "devel@monitoring-plugins.org"; | ||
| 36 | |||
| 37 | #define REPLICA_RESULTSIZE 96 | ||
| 38 | |||
| 39 | #include "common.h" | 33 | #include "common.h" |
| 34 | #include "output.h" | ||
| 35 | #include "perfdata.h" | ||
| 36 | #include "states.h" | ||
| 37 | #include "thresholds.h" | ||
| 40 | #include "utils.h" | 38 | #include "utils.h" |
| 41 | #include "utils_base.h" | 39 | #include "utils_base.h" |
| 42 | #include "netutils.h" | 40 | #include "netutils.h" |
| @@ -46,8 +44,14 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 46 | #include <mysqld_error.h> | 44 | #include <mysqld_error.h> |
| 47 | #include <errmsg.h> | 45 | #include <errmsg.h> |
| 48 | 46 | ||
| 47 | const char *progname = "check_mysql"; | ||
| 48 | const char *copyright = "1999-2024"; | ||
| 49 | const char *email = "devel@monitoring-plugins.org"; | ||
| 50 | |||
| 49 | static int verbose = 0; | 51 | static int verbose = 0; |
| 50 | 52 | ||
| 53 | #define REPLICA_RESULTSIZE 96 | ||
| 54 | |||
| 51 | #define LENGTH_METRIC_UNIT 6 | 55 | #define LENGTH_METRIC_UNIT 6 |
| 52 | static const char *metric_unit[LENGTH_METRIC_UNIT] = { | 56 | static const char *metric_unit[LENGTH_METRIC_UNIT] = { |
| 53 | "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", | 57 | "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", |
| @@ -110,7 +114,11 @@ int main(int argc, char **argv) { | |||
| 110 | mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, | 114 | mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, |
| 111 | config.ciphers); | 115 | config.ciphers); |
| 112 | } | 116 | } |
| 113 | /* establish a connection to the server and error checking */ | 117 | |
| 118 | mp_check overall = mp_check_init(); | ||
| 119 | |||
| 120 | mp_subcheck sc_connection = mp_subcheck_init(); | ||
| 121 | /* establish a connection to the server and check for errors */ | ||
| 114 | if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, | 122 | if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, |
| 115 | config.db_port, config.db_socket, 0)) { | 123 | config.db_port, config.db_socket, 0)) { |
| 116 | /* Depending on internally-selected auth plugin MySQL might return */ | 124 | /* Depending on internally-selected auth plugin MySQL might return */ |
| @@ -118,78 +126,115 @@ int main(int argc, char **argv) { | |||
| 118 | /* Semantically these errors are the same. */ | 126 | /* Semantically these errors are the same. */ |
| 119 | if (config.ignore_auth && (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || | 127 | if (config.ignore_auth && (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || |
| 120 | mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) { | 128 | mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) { |
| 121 | printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql), | 129 | xasprintf(&sc_connection.output, "Version: %s (protocol %d)", |
| 122 | mysql_get_proto_info(&mysql)); | 130 | mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql)); |
| 123 | mysql_close(&mysql); | 131 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK); |
| 124 | return STATE_OK; | ||
| 125 | } | ||
| 126 | 132 | ||
| 127 | if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { | 133 | mysql_close(&mysql); |
| 128 | die(STATE_WARNING, "%s\n", mysql_error(&mysql)); | ||
| 129 | } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) { | ||
| 130 | die(STATE_WARNING, "%s\n", mysql_error(&mysql)); | ||
| 131 | } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) { | ||
| 132 | die(STATE_WARNING, "%s\n", mysql_error(&mysql)); | ||
| 133 | } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) { | ||
| 134 | die(STATE_WARNING, "%s\n", mysql_error(&mysql)); | ||
| 135 | } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) { | ||
| 136 | die(STATE_WARNING, "%s\n", mysql_error(&mysql)); | ||
| 137 | } else { | 134 | } else { |
| 138 | die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); | 135 | if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { |
| 136 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); | ||
| 137 | xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); | ||
| 138 | } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) { | ||
| 139 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); | ||
| 140 | xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); | ||
| 141 | } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) { | ||
| 142 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); | ||
| 143 | xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); | ||
| 144 | } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) { | ||
| 145 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); | ||
| 146 | xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); | ||
| 147 | } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) { | ||
| 148 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); | ||
| 149 | xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); | ||
| 150 | } else { | ||
| 151 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_CRITICAL); | ||
| 152 | xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); | ||
| 153 | } | ||
| 139 | } | 154 | } |
| 155 | |||
| 156 | mp_add_subcheck_to_check(&overall, sc_connection); | ||
| 157 | mp_exit(overall); | ||
| 158 | } else { | ||
| 159 | // successful connection | ||
| 160 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK); | ||
| 161 | xasprintf(&sc_connection.output, "Version: %s (protocol %d)", mysql_get_server_info(&mysql), | ||
| 162 | mysql_get_proto_info(&mysql)); | ||
| 163 | mp_add_subcheck_to_check(&overall, sc_connection); | ||
| 140 | } | 164 | } |
| 141 | 165 | ||
| 142 | /* get the server stats */ | 166 | /* get the server stats */ |
| 143 | char *result = strdup(mysql_stat(&mysql)); | 167 | char *mysql_stats = strdup(mysql_stat(&mysql)); |
| 168 | |||
| 169 | mp_subcheck sc_stats = mp_subcheck_init(); | ||
| 170 | sc_stats = mp_set_subcheck_default_state(sc_stats, STATE_OK); | ||
| 144 | 171 | ||
| 145 | /* error checking once more */ | 172 | /* error checking once more */ |
| 146 | if (mysql_error(&mysql)) { | 173 | if (mysql_errno(&mysql) != 0) { |
| 147 | if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) { | 174 | if ((mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) || |
| 148 | die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); | 175 | (mysql_errno(&mysql) == CR_SERVER_LOST) || (mysql_errno(&mysql) == CR_UNKNOWN_ERROR)) { |
| 149 | } else if (mysql_errno(&mysql) == CR_SERVER_LOST) { | 176 | sc_stats = mp_set_subcheck_state(sc_stats, STATE_CRITICAL); |
| 150 | die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); | 177 | xasprintf(&sc_stats.output, "Retrieving stats failed: %s", mysql_error(&mysql)); |
| 151 | } else if (mysql_errno(&mysql) == CR_UNKNOWN_ERROR) { | 178 | } else { |
| 152 | die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); | 179 | // not sure which error modes occur here, but mysql_error indicates an error |
| 180 | sc_stats = mp_set_subcheck_state(sc_stats, STATE_WARNING); | ||
| 181 | xasprintf(&sc_stats.output, "retrieving stats caused an error: %s", | ||
| 182 | mysql_error(&mysql)); | ||
| 153 | } | 183 | } |
| 184 | |||
| 185 | mp_add_subcheck_to_check(&overall, sc_stats); | ||
| 186 | mp_exit(overall); | ||
| 187 | } else { | ||
| 188 | xasprintf(&sc_stats.output, "retrieved stats: %s", mysql_stats); | ||
| 189 | sc_stats = mp_set_subcheck_state(sc_stats, STATE_OK); | ||
| 190 | mp_add_subcheck_to_check(&overall, sc_stats); | ||
| 154 | } | 191 | } |
| 155 | 192 | ||
| 156 | char *perf = strdup(""); | ||
| 157 | char *error = NULL; | ||
| 158 | MYSQL_RES *res; | 193 | MYSQL_RES *res; |
| 159 | MYSQL_ROW row; | 194 | MYSQL_ROW row; |
| 195 | mp_subcheck sc_query = mp_subcheck_init(); | ||
| 160 | /* try to fetch some perf data */ | 196 | /* try to fetch some perf data */ |
| 161 | if (mysql_query(&mysql, "show global status") == 0) { | 197 | if (mysql_query(&mysql, "show global status") == 0) { |
| 162 | if ((res = mysql_store_result(&mysql)) == NULL) { | 198 | if ((res = mysql_store_result(&mysql)) == NULL) { |
| 163 | error = strdup(mysql_error(&mysql)); | 199 | xasprintf(&sc_connection.output, "query failed - status store_result error: %s", |
| 200 | mysql_error(&mysql)); | ||
| 164 | mysql_close(&mysql); | 201 | mysql_close(&mysql); |
| 165 | die(STATE_CRITICAL, _("status store_result error: %s\n"), error); | 202 | |
| 203 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 204 | mp_add_subcheck_to_check(&overall, sc_query); | ||
| 205 | mp_exit(overall); | ||
| 166 | } | 206 | } |
| 167 | 207 | ||
| 168 | while ((row = mysql_fetch_row(res)) != NULL) { | 208 | while ((row = mysql_fetch_row(res)) != NULL) { |
| 169 | for (int i = 0; i < LENGTH_METRIC_UNIT; i++) { | 209 | for (int i = 0; i < LENGTH_METRIC_UNIT; i++) { |
| 170 | if (strcmp(row[0], metric_unit[i]) == 0) { | 210 | if (strcmp(row[0], metric_unit[i]) == 0) { |
| 171 | xasprintf(&perf, "%s%s ", perf, | 211 | mp_perfdata pd_mysql_stat = perfdata_init(); |
| 172 | perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false, | 212 | pd_mysql_stat.label = (char *)metric_unit[i]; |
| 173 | 0, false, 0)); | 213 | pd_mysql_stat.value = mp_create_pd_value(atol(row[1])); |
| 214 | mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat); | ||
| 174 | continue; | 215 | continue; |
| 175 | } | 216 | } |
| 176 | } | 217 | } |
| 218 | |||
| 177 | for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) { | 219 | for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) { |
| 178 | if (strcmp(row[0], metric_counter[i]) == 0) { | 220 | if (strcmp(row[0], metric_counter[i]) == 0) { |
| 179 | xasprintf(&perf, "%s%s ", perf, | 221 | mp_perfdata pd_mysql_stat = perfdata_init(); |
| 180 | perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0, | 222 | pd_mysql_stat.label = (char *)metric_counter[i]; |
| 181 | false, 0, false, 0)); | 223 | pd_mysql_stat.value = mp_create_pd_value(atol(row[1])); |
| 224 | pd_mysql_stat.uom = "c"; | ||
| 225 | mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat); | ||
| 182 | continue; | 226 | continue; |
| 183 | } | 227 | } |
| 184 | } | 228 | } |
| 185 | } | 229 | } |
| 186 | /* remove trailing space */ | 230 | } else { |
| 187 | if (strlen(perf) > 0) { | 231 | // Query failed! |
| 188 | perf[strlen(perf) - 1] = '\0'; | 232 | xasprintf(&sc_connection.output, "query failed"); |
| 189 | } | 233 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); |
| 234 | mp_add_subcheck_to_check(&overall, sc_query); | ||
| 235 | mp_exit(overall); | ||
| 190 | } | 236 | } |
| 191 | 237 | ||
| 192 | char replica_result[REPLICA_RESULTSIZE] = {0}; | ||
| 193 | if (config.check_replica) { | 238 | if (config.check_replica) { |
| 194 | // Detect which version we are, on older version | 239 | // Detect which version we are, on older version |
| 195 | // "show slave status" should work, on newer ones | 240 | // "show slave status" should work, on newer ones |
| @@ -203,8 +248,10 @@ int main(int argc, char **argv) { | |||
| 203 | unsigned long major_version = server_verion_int / 10000; | 248 | unsigned long major_version = server_verion_int / 10000; |
| 204 | unsigned long minor_version = (server_verion_int % 10000) / 100; | 249 | unsigned long minor_version = (server_verion_int % 10000) / 100; |
| 205 | unsigned long patch_version = (server_verion_int % 100); | 250 | unsigned long patch_version = (server_verion_int % 100); |
| 251 | |||
| 206 | if (verbose) { | 252 | if (verbose) { |
| 207 | printf("Found MariaDB: %s, main version: %lu, minor version: %lu, patch version: %lu\n", | 253 | printf("Found MariaDB/MySQL: %s, main version: %lu, minor version: %lu, patch version: " |
| 254 | "%lu\n", | ||
| 208 | server_version, major_version, minor_version, patch_version); | 255 | server_version, major_version, minor_version, patch_version); |
| 209 | } | 256 | } |
| 210 | 257 | ||
| @@ -235,43 +282,60 @@ int main(int argc, char **argv) { | |||
| 235 | replica_query = "show replica status"; | 282 | replica_query = "show replica status"; |
| 236 | } | 283 | } |
| 237 | 284 | ||
| 285 | mp_subcheck sc_replica = mp_subcheck_init(); | ||
| 286 | |||
| 238 | /* check the replica status */ | 287 | /* check the replica status */ |
| 239 | if (mysql_query(&mysql, replica_query) != 0) { | 288 | if (mysql_query(&mysql, replica_query) != 0) { |
| 240 | error = strdup(mysql_error(&mysql)); | 289 | xasprintf(&sc_replica.output, "replica query error: %s", mysql_error(&mysql)); |
| 241 | mysql_close(&mysql); | 290 | mysql_close(&mysql); |
| 242 | die(STATE_CRITICAL, _("replica query error: %s\n"), error); | 291 | |
| 292 | sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); | ||
| 293 | mp_add_subcheck_to_check(&overall, sc_replica); | ||
| 294 | mp_exit(overall); | ||
| 243 | } | 295 | } |
| 244 | 296 | ||
| 245 | /* store the result */ | 297 | /* store the result */ |
| 246 | if ((res = mysql_store_result(&mysql)) == NULL) { | 298 | if ((res = mysql_store_result(&mysql)) == NULL) { |
| 247 | error = strdup(mysql_error(&mysql)); | 299 | xasprintf(&sc_replica.output, "replica store_result error: %s", mysql_error(&mysql)); |
| 248 | mysql_close(&mysql); | 300 | mysql_close(&mysql); |
| 249 | die(STATE_CRITICAL, _("replica store_result error: %s\n"), error); | 301 | |
| 302 | sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); | ||
| 303 | mp_add_subcheck_to_check(&overall, sc_replica); | ||
| 304 | mp_exit(overall); | ||
| 250 | } | 305 | } |
| 251 | 306 | ||
| 252 | /* Check there is some data */ | 307 | /* Check there is some data */ |
| 253 | if (mysql_num_rows(res) == 0) { | 308 | if (mysql_num_rows(res) == 0) { |
| 254 | mysql_close(&mysql); | 309 | mysql_close(&mysql); |
| 255 | die(STATE_WARNING, "%s\n", _("No replicas defined")); | 310 | |
| 311 | xasprintf(&sc_replica.output, "no replicas defined"); | ||
| 312 | sc_replica = mp_set_subcheck_state(sc_replica, STATE_WARNING); | ||
| 313 | mp_add_subcheck_to_check(&overall, sc_replica); | ||
| 314 | mp_exit(overall); | ||
| 256 | } | 315 | } |
| 257 | 316 | ||
| 258 | /* fetch the first row */ | 317 | /* fetch the first row */ |
| 259 | if ((row = mysql_fetch_row(res)) == NULL) { | 318 | if ((row = mysql_fetch_row(res)) == NULL) { |
| 260 | error = strdup(mysql_error(&mysql)); | 319 | xasprintf(&sc_replica.output, "replica fetch row error: %s", mysql_error(&mysql)); |
| 261 | mysql_free_result(res); | 320 | mysql_free_result(res); |
| 262 | mysql_close(&mysql); | 321 | mysql_close(&mysql); |
| 263 | die(STATE_CRITICAL, _("replica fetch row error: %s\n"), error); | 322 | |
| 323 | sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); | ||
| 324 | mp_add_subcheck_to_check(&overall, sc_replica); | ||
| 325 | mp_exit(overall); | ||
| 264 | } | 326 | } |
| 265 | 327 | ||
| 266 | if (mysql_field_count(&mysql) == 12) { | 328 | if (mysql_field_count(&mysql) == 12) { |
| 267 | /* mysql 3.23.x */ | 329 | /* mysql 3.23.x */ |
| 268 | snprintf(replica_result, REPLICA_RESULTSIZE, _("Replica running: %s"), row[6]); | 330 | xasprintf(&sc_replica.output, "Replica running: %s", row[6]); |
| 269 | if (strcmp(row[6], "Yes") != 0) { | 331 | if (strcmp(row[6], "Yes") != 0) { |
| 270 | mysql_free_result(res); | 332 | mysql_free_result(res); |
| 271 | mysql_close(&mysql); | 333 | mysql_close(&mysql); |
| 272 | die(STATE_CRITICAL, "%s\n", replica_result); | ||
| 273 | } | ||
| 274 | 334 | ||
| 335 | sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); | ||
| 336 | mp_add_subcheck_to_check(&overall, sc_replica); | ||
| 337 | mp_exit(overall); | ||
| 338 | } | ||
| 275 | } else { | 339 | } else { |
| 276 | /* mysql 4.x.x and mysql 5.x.x */ | 340 | /* mysql 4.x.x and mysql 5.x.x */ |
| 277 | int replica_io_field = -1; | 341 | int replica_io_field = -1; |
| @@ -315,14 +379,18 @@ int main(int argc, char **argv) { | |||
| 315 | if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) { | 379 | if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) { |
| 316 | mysql_free_result(res); | 380 | mysql_free_result(res); |
| 317 | mysql_close(&mysql); | 381 | mysql_close(&mysql); |
| 318 | die(STATE_CRITICAL, "Replica status unavailable\n"); | 382 | |
| 383 | xasprintf(&sc_replica.output, "Replica status unavailable"); | ||
| 384 | sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); | ||
| 385 | mp_add_subcheck_to_check(&overall, sc_replica); | ||
| 386 | mp_exit(overall); | ||
| 319 | } | 387 | } |
| 320 | 388 | ||
| 321 | /* Save replica status in replica_result */ | 389 | /* Save replica status in replica_result */ |
| 322 | snprintf(replica_result, REPLICA_RESULTSIZE, | 390 | xasprintf(&sc_replica.output, |
| 323 | "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s", | 391 | "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s", |
| 324 | row[replica_io_field], row[replica_sql_field], | 392 | row[replica_io_field], row[replica_sql_field], |
| 325 | seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown"); | 393 | seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown"); |
| 326 | 394 | ||
| 327 | /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no | 395 | /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no |
| 328 | * mysqldump threads running */ | 396 | * mysqldump threads running */ |
| @@ -345,10 +413,14 @@ int main(int argc, char **argv) { | |||
| 345 | } | 413 | } |
| 346 | mysql_close(&mysql); | 414 | mysql_close(&mysql); |
| 347 | } | 415 | } |
| 416 | |||
| 348 | if (mysqldump_threads == 0) { | 417 | if (mysqldump_threads == 0) { |
| 349 | die(STATE_CRITICAL, "%s\n", replica_result); | 418 | sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); |
| 419 | mp_add_subcheck_to_check(&overall, sc_replica); | ||
| 420 | mp_exit(overall); | ||
| 350 | } else { | 421 | } else { |
| 351 | strncat(replica_result, " Mysqldump: in progress", REPLICA_RESULTSIZE - 1); | 422 | xasprintf(&sc_replica.output, "%s %s", sc_replica.output, |
| 423 | " Mysqldump: in progress"); | ||
| 352 | } | 424 | } |
| 353 | } | 425 | } |
| 354 | 426 | ||
| @@ -364,22 +436,22 @@ int main(int argc, char **argv) { | |||
| 364 | /* Check Seconds Behind against threshold */ | 436 | /* Check Seconds Behind against threshold */ |
| 365 | if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && | 437 | if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && |
| 366 | strcmp(row[seconds_behind_field], "NULL") != 0)) { | 438 | strcmp(row[seconds_behind_field], "NULL") != 0)) { |
| 367 | double value = atof(row[seconds_behind_field]); | 439 | mp_perfdata pd_seconds_behind = perfdata_init(); |
| 368 | int status; | 440 | pd_seconds_behind.label = "seconds behind master"; |
| 369 | 441 | pd_seconds_behind.value = mp_create_pd_value(atof(row[seconds_behind_field])); | |
| 370 | status = get_status(value, config.my_threshold); | 442 | pd_seconds_behind = |
| 371 | 443 | mp_pd_set_thresholds(pd_seconds_behind, config.replica_thresholds); | |
| 372 | xasprintf(&perf, "%s %s", perf, | 444 | pd_seconds_behind.uom = "s"; |
| 373 | fperfdata("seconds behind master", value, "s", true, | 445 | mp_add_perfdata_to_subcheck(&sc_replica, pd_seconds_behind); |
| 374 | (double)config.warning_time, true, (double)config.critical_time, | 446 | |
| 375 | false, 0, false, 0)); | 447 | mp_state_enum status = mp_get_pd_status(pd_seconds_behind); |
| 376 | 448 | ||
| 377 | if (status == STATE_WARNING) { | 449 | sc_replica = mp_set_subcheck_state(sc_replica, status); |
| 378 | printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf); | 450 | |
| 379 | exit(STATE_WARNING); | 451 | if (status != STATE_OK) { |
| 380 | } else if (status == STATE_CRITICAL) { | 452 | xasprintf(&sc_replica.output, "slow replica - %s", sc_replica.output); |
| 381 | printf("SLOW_REPLICA %s: %s|%s\n", _("CRITICAL"), replica_result, perf); | 453 | mp_add_subcheck_to_check(&overall, sc_replica); |
| 382 | exit(STATE_CRITICAL); | 454 | mp_exit(overall); |
| 383 | } | 455 | } |
| 384 | } | 456 | } |
| 385 | } | 457 | } |
| @@ -391,20 +463,16 @@ int main(int argc, char **argv) { | |||
| 391 | /* close the connection */ | 463 | /* close the connection */ |
| 392 | mysql_close(&mysql); | 464 | mysql_close(&mysql); |
| 393 | 465 | ||
| 394 | /* print out the result of stats */ | 466 | mp_exit(overall); |
| 395 | if (config.check_replica) { | ||
| 396 | printf("%s %s|%s\n", result, replica_result, perf); | ||
| 397 | } else { | ||
| 398 | printf("%s|%s\n", result, perf); | ||
| 399 | } | ||
| 400 | |||
| 401 | return STATE_OK; | ||
| 402 | } | 467 | } |
| 403 | 468 | ||
| 404 | #define CHECK_REPLICA_OPT CHAR_MAX + 1 | ||
| 405 | |||
| 406 | /* process command-line arguments */ | 469 | /* process command-line arguments */ |
| 407 | check_mysql_config_wrapper process_arguments(int argc, char **argv) { | 470 | check_mysql_config_wrapper process_arguments(int argc, char **argv) { |
| 471 | |||
| 472 | enum { | ||
| 473 | CHECK_REPLICA_OPT = CHAR_MAX + 1, | ||
| 474 | }; | ||
| 475 | |||
| 408 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, | 476 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, |
| 409 | {"socket", required_argument, 0, 's'}, | 477 | {"socket", required_argument, 0, 's'}, |
| 410 | {"database", required_argument, 0, 'd'}, | 478 | {"database", required_argument, 0, 'd'}, |
| @@ -439,9 +507,6 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 439 | return result; | 507 | return result; |
| 440 | } | 508 | } |
| 441 | 509 | ||
| 442 | char *warning = NULL; | ||
| 443 | char *critical = NULL; | ||
| 444 | |||
| 445 | int option = 0; | 510 | int option = 0; |
| 446 | while (true) { | 511 | while (true) { |
| 447 | int option_index = | 512 | int option_index = |
| @@ -513,14 +578,22 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 513 | case 'n': | 578 | case 'n': |
| 514 | result.config.ignore_auth = true; /* ignore-auth */ | 579 | result.config.ignore_auth = true; /* ignore-auth */ |
| 515 | break; | 580 | break; |
| 516 | case 'w': | 581 | case 'w': { |
| 517 | warning = optarg; | 582 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 518 | result.config.warning_time = strtod(warning, NULL); | 583 | if (tmp.error != MP_PARSING_SUCCES) { |
| 519 | break; | 584 | die(STATE_UNKNOWN, "failed to parse warning time threshold"); |
| 520 | case 'c': | 585 | } |
| 521 | critical = optarg; | 586 | result.config.replica_thresholds = |
| 522 | result.config.critical_time = strtod(critical, NULL); | 587 | mp_thresholds_set_warn(result.config.replica_thresholds, tmp.range); |
| 523 | break; | 588 | } break; |
| 589 | case 'c': { | ||
| 590 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 591 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 592 | die(STATE_UNKNOWN, "failed to parse critical time threshold"); | ||
| 593 | } | ||
| 594 | result.config.replica_thresholds = | ||
| 595 | mp_thresholds_set_crit(result.config.replica_thresholds, tmp.range); | ||
| 596 | } break; | ||
| 524 | case 'V': /* version */ | 597 | case 'V': /* version */ |
| 525 | print_revision(progname, NP_VERSION); | 598 | print_revision(progname, NP_VERSION); |
| 526 | exit(STATE_UNKNOWN); | 599 | exit(STATE_UNKNOWN); |
| @@ -537,8 +610,6 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 537 | 610 | ||
| 538 | int index = optind; | 611 | int index = optind; |
| 539 | 612 | ||
| 540 | set_thresholds(&result.config.my_threshold, warning, critical); | ||
| 541 | |||
| 542 | while (argc > index) { | 613 | while (argc > index) { |
| 543 | if (result.config.db_host == NULL) { | 614 | if (result.config.db_host == NULL) { |
| 544 | if (is_host(argv[index])) { | 615 | if (is_host(argv[index])) { |
diff --git a/plugins/check_mysql.d/config.h b/plugins/check_mysql.d/config.h index 71ddbe8d..ef086cfc 100644 --- a/plugins/check_mysql.d/config.h +++ b/plugins/check_mysql.d/config.h | |||
| @@ -24,9 +24,7 @@ typedef struct { | |||
| 24 | bool check_replica; | 24 | bool check_replica; |
| 25 | bool ignore_auth; | 25 | bool ignore_auth; |
| 26 | 26 | ||
| 27 | double warning_time; | 27 | mp_thresholds replica_thresholds; |
| 28 | double critical_time; | ||
| 29 | thresholds *my_threshold; | ||
| 30 | 28 | ||
| 31 | } check_mysql_config; | 29 | } check_mysql_config; |
| 32 | 30 | ||
| @@ -50,9 +48,7 @@ check_mysql_config check_mysql_config_init() { | |||
| 50 | .check_replica = false, | 48 | .check_replica = false, |
| 51 | .ignore_auth = false, | 49 | .ignore_auth = false, |
| 52 | 50 | ||
| 53 | .warning_time = 0, | 51 | .replica_thresholds = mp_thresholds_init(), |
| 54 | .critical_time = 0, | ||
| 55 | .my_threshold = NULL, | ||
| 56 | }; | 52 | }; |
| 57 | return tmp; | 53 | return tmp; |
| 58 | } | 54 | } |
diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c index c7e84deb..8af378d5 100644 --- a/plugins/check_mysql_query.c +++ b/plugins/check_mysql_query.c | |||
| @@ -29,11 +29,11 @@ | |||
| 29 | * | 29 | * |
| 30 | *****************************************************************************/ | 30 | *****************************************************************************/ |
| 31 | 31 | ||
| 32 | const char *progname = "check_mysql_query"; | ||
| 33 | const char *copyright = "1999-2024"; | ||
| 34 | const char *email = "devel@monitoring-plugins.org"; | ||
| 35 | |||
| 36 | #include "common.h" | 32 | #include "common.h" |
| 33 | #include "output.h" | ||
| 34 | #include "perfdata.h" | ||
| 35 | #include "states.h" | ||
| 36 | #include "thresholds.h" | ||
| 37 | #include "utils.h" | 37 | #include "utils.h" |
| 38 | #include "utils_base.h" | 38 | #include "utils_base.h" |
| 39 | #include "netutils.h" | 39 | #include "netutils.h" |
| @@ -42,6 +42,10 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 42 | #include <mysql.h> | 42 | #include <mysql.h> |
| 43 | #include <errmsg.h> | 43 | #include <errmsg.h> |
| 44 | 44 | ||
| 45 | const char *progname = "check_mysql_query"; | ||
| 46 | const char *copyright = "1999-2024"; | ||
| 47 | const char *email = "devel@monitoring-plugins.org"; | ||
| 48 | |||
| 45 | typedef struct { | 49 | typedef struct { |
| 46 | int errorcode; | 50 | int errorcode; |
| 47 | check_mysql_query_config config; | 51 | check_mysql_query_config config; |
| @@ -83,27 +87,38 @@ int main(int argc, char **argv) { | |||
| 83 | mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client"); | 87 | mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client"); |
| 84 | } | 88 | } |
| 85 | 89 | ||
| 90 | mp_check overall = mp_check_init(); | ||
| 91 | mp_subcheck sc_connect = mp_subcheck_init(); | ||
| 92 | |||
| 86 | /* establish a connection to the server and error checking */ | 93 | /* establish a connection to the server and error checking */ |
| 87 | if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, | 94 | if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, |
| 88 | config.db_port, config.db_socket, 0)) { | 95 | config.db_port, config.db_socket, 0)) { |
| 96 | xasprintf(&sc_connect.output, "query failed: %s", mysql_error(&mysql)); | ||
| 97 | |||
| 89 | if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { | 98 | if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { |
| 90 | die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); | 99 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); |
| 91 | } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) { | 100 | } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) { |
| 92 | die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); | 101 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); |
| 93 | } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) { | 102 | } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) { |
| 94 | die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); | 103 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); |
| 95 | } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) { | 104 | } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) { |
| 96 | die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); | 105 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); |
| 97 | } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) { | 106 | } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) { |
| 98 | die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); | 107 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); |
| 99 | } else { | 108 | } else { |
| 100 | die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql)); | 109 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_CRITICAL); |
| 101 | } | 110 | } |
| 111 | |||
| 112 | mp_add_subcheck_to_check(&overall, sc_connect); | ||
| 113 | mp_exit(overall); | ||
| 102 | } | 114 | } |
| 103 | 115 | ||
| 104 | char *error = NULL; | 116 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_OK); |
| 117 | xasprintf(&sc_connect.output, "query succeeded"); | ||
| 118 | mp_add_subcheck_to_check(&overall, sc_connect); | ||
| 119 | |||
| 105 | if (mysql_query(&mysql, config.sql_query) != 0) { | 120 | if (mysql_query(&mysql, config.sql_query) != 0) { |
| 106 | error = strdup(mysql_error(&mysql)); | 121 | char *error = strdup(mysql_error(&mysql)); |
| 107 | mysql_close(&mysql); | 122 | mysql_close(&mysql); |
| 108 | die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error); | 123 | die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error); |
| 109 | } | 124 | } |
| @@ -111,7 +126,7 @@ int main(int argc, char **argv) { | |||
| 111 | MYSQL_RES *res; | 126 | MYSQL_RES *res; |
| 112 | /* store the result */ | 127 | /* store the result */ |
| 113 | if ((res = mysql_store_result(&mysql)) == NULL) { | 128 | if ((res = mysql_store_result(&mysql)) == NULL) { |
| 114 | error = strdup(mysql_error(&mysql)); | 129 | char *error = strdup(mysql_error(&mysql)); |
| 115 | mysql_close(&mysql); | 130 | mysql_close(&mysql); |
| 116 | die(STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error); | 131 | die(STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error); |
| 117 | } | 132 | } |
| @@ -122,17 +137,24 @@ int main(int argc, char **argv) { | |||
| 122 | die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned")); | 137 | die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned")); |
| 123 | } | 138 | } |
| 124 | 139 | ||
| 140 | mp_subcheck sc_value = mp_subcheck_init(); | ||
| 125 | MYSQL_ROW row; | 141 | MYSQL_ROW row; |
| 126 | /* fetch the first row */ | 142 | /* fetch the first row */ |
| 127 | if ((row = mysql_fetch_row(res)) == NULL) { | 143 | if ((row = mysql_fetch_row(res)) == NULL) { |
| 128 | error = strdup(mysql_error(&mysql)); | 144 | xasprintf(&sc_value.output, "fetch row error - %s", mysql_error(&mysql)); |
| 129 | mysql_free_result(res); | 145 | mysql_free_result(res); |
| 130 | mysql_close(&mysql); | 146 | mysql_close(&mysql); |
| 131 | die(STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error); | 147 | |
| 148 | sc_value = mp_set_subcheck_state(sc_value, STATE_CRITICAL); | ||
| 149 | mp_add_subcheck_to_check(&overall, sc_value); | ||
| 150 | mp_exit(overall); | ||
| 132 | } | 151 | } |
| 133 | 152 | ||
| 134 | if (!is_numeric(row[0])) { | 153 | if (!is_numeric(row[0])) { |
| 135 | die(STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]); | 154 | xasprintf(&sc_value.output, "query result is not numeric"); |
| 155 | sc_value = mp_set_subcheck_state(sc_value, STATE_CRITICAL); | ||
| 156 | mp_add_subcheck_to_check(&overall, sc_value); | ||
| 157 | mp_exit(overall); | ||
| 136 | } | 158 | } |
| 137 | 159 | ||
| 138 | double value = strtod(row[0], NULL); | 160 | double value = strtod(row[0], NULL); |
| @@ -147,24 +169,18 @@ int main(int argc, char **argv) { | |||
| 147 | printf("mysql result: %f\n", value); | 169 | printf("mysql result: %f\n", value); |
| 148 | } | 170 | } |
| 149 | 171 | ||
| 150 | int status = get_status(value, config.my_thresholds); | 172 | mp_perfdata pd_query_result = perfdata_init(); |
| 173 | pd_query_result = mp_set_pd_value(pd_query_result, value); | ||
| 174 | pd_query_result = mp_pd_set_thresholds(pd_query_result, config.thresholds); | ||
| 175 | pd_query_result.label = "result"; | ||
| 176 | mp_add_perfdata_to_subcheck(&sc_value, pd_query_result); | ||
| 151 | 177 | ||
| 152 | if (status == STATE_OK) { | 178 | sc_value = mp_set_subcheck_state(sc_value, mp_get_pd_status(pd_query_result)); |
| 153 | printf("QUERY %s: ", _("OK")); | 179 | xasprintf(&sc_value.output, "'%s' returned '%f'", config.sql_query, value); |
| 154 | } else if (status == STATE_WARNING) { | 180 | |
| 155 | printf("QUERY %s: ", _("WARNING")); | 181 | mp_add_subcheck_to_check(&overall, sc_value); |
| 156 | } else if (status == STATE_CRITICAL) { | ||
| 157 | printf("QUERY %s: ", _("CRITICAL")); | ||
| 158 | } | ||
| 159 | printf(_("'%s' returned %f | %s"), config.sql_query, value, | ||
| 160 | fperfdata("result", value, "", config.my_thresholds->warning, | ||
| 161 | config.my_thresholds->warning ? config.my_thresholds->warning->end : 0, | ||
| 162 | config.my_thresholds->critical, | ||
| 163 | config.my_thresholds->critical ? config.my_thresholds->critical->end : 0, | ||
| 164 | false, 0, false, 0)); | ||
| 165 | printf("\n"); | ||
| 166 | 182 | ||
| 167 | return status; | 183 | mp_exit(overall); |
| 168 | } | 184 | } |
| 169 | 185 | ||
| 170 | /* process command-line arguments */ | 186 | /* process command-line arguments */ |
| @@ -195,9 +211,6 @@ check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { | |||
| 195 | return result; | 211 | return result; |
| 196 | } | 212 | } |
| 197 | 213 | ||
| 198 | char *warning = NULL; | ||
| 199 | char *critical = NULL; | ||
| 200 | |||
| 201 | while (true) { | 214 | while (true) { |
| 202 | int option = 0; | 215 | int option = 0; |
| 203 | int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option); | 216 | int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option); |
| @@ -253,19 +266,25 @@ check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { | |||
| 253 | case 'q': | 266 | case 'q': |
| 254 | xasprintf(&result.config.sql_query, "%s", optarg); | 267 | xasprintf(&result.config.sql_query, "%s", optarg); |
| 255 | break; | 268 | break; |
| 256 | case 'w': | 269 | case 'w': { |
| 257 | warning = optarg; | 270 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 258 | break; | 271 | if (tmp.error != MP_PARSING_SUCCES) { |
| 259 | case 'c': | 272 | die(STATE_UNKNOWN, "failed to parse warning threshold"); |
| 260 | critical = optarg; | 273 | } |
| 261 | break; | 274 | result.config.thresholds = mp_thresholds_set_warn(result.config.thresholds, tmp.range); |
| 275 | } break; | ||
| 276 | case 'c': { | ||
| 277 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 278 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 279 | die(STATE_UNKNOWN, "failed to parse critical threshold"); | ||
| 280 | } | ||
| 281 | result.config.thresholds = mp_thresholds_set_crit(result.config.thresholds, tmp.range); | ||
| 282 | } break; | ||
| 262 | case '?': /* help */ | 283 | case '?': /* help */ |
| 263 | usage5(); | 284 | usage5(); |
| 264 | } | 285 | } |
| 265 | } | 286 | } |
| 266 | 287 | ||
| 267 | set_thresholds(&result.config.my_thresholds, warning, critical); | ||
| 268 | |||
| 269 | return validate_arguments(result); | 288 | return validate_arguments(result); |
| 270 | } | 289 | } |
| 271 | 290 | ||
diff --git a/plugins/check_mysql_query.d/config.h b/plugins/check_mysql_query.d/config.h index be019160..1c9952e5 100644 --- a/plugins/check_mysql_query.d/config.h +++ b/plugins/check_mysql_query.d/config.h | |||
| @@ -15,7 +15,7 @@ typedef struct { | |||
| 15 | unsigned int db_port; | 15 | unsigned int db_port; |
| 16 | 16 | ||
| 17 | char *sql_query; | 17 | char *sql_query; |
| 18 | thresholds *my_thresholds; | 18 | mp_thresholds thresholds; |
| 19 | } check_mysql_query_config; | 19 | } check_mysql_query_config; |
| 20 | 20 | ||
| 21 | check_mysql_query_config check_mysql_query_config_init() { | 21 | check_mysql_query_config check_mysql_query_config_init() { |
| @@ -30,7 +30,7 @@ check_mysql_query_config check_mysql_query_config_init() { | |||
| 30 | .db_port = MYSQL_PORT, | 30 | .db_port = MYSQL_PORT, |
| 31 | 31 | ||
| 32 | .sql_query = NULL, | 32 | .sql_query = NULL, |
| 33 | .my_thresholds = NULL, | 33 | .thresholds = mp_thresholds_init(), |
| 34 | }; | 34 | }; |
| 35 | return tmp; | 35 | return tmp; |
| 36 | } | 36 | } |
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c index 24d1c9b5..f7cad630 100644 --- a/plugins/check_ntp_peer.c +++ b/plugins/check_ntp_peer.c | |||
| @@ -35,11 +35,14 @@ | |||
| 35 | * | 35 | * |
| 36 | *****************************************************************************/ | 36 | *****************************************************************************/ |
| 37 | 37 | ||
| 38 | #include "thresholds.h" | ||
| 39 | const char *progname = "check_ntp_peer"; | 38 | const char *progname = "check_ntp_peer"; |
| 40 | const char *copyright = "2006-2024"; | 39 | const char *copyright = "2006-2024"; |
| 41 | const char *email = "devel@monitoring-plugins.org"; | 40 | const char *email = "devel@monitoring-plugins.org"; |
| 42 | 41 | ||
| 42 | #include "output.h" | ||
| 43 | #include "perfdata.h" | ||
| 44 | #include <openssl/x509.h> | ||
| 45 | #include "thresholds.h" | ||
| 43 | #include "common.h" | 46 | #include "common.h" |
| 44 | #include "netutils.h" | 47 | #include "netutils.h" |
| 45 | #include "utils.h" | 48 | #include "utils.h" |
| @@ -47,8 +50,6 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 47 | #include "check_ntp_peer.d/config.h" | 50 | #include "check_ntp_peer.d/config.h" |
| 48 | 51 | ||
| 49 | static int verbose = 0; | 52 | static int verbose = 0; |
| 50 | static bool syncsource_found = false; | ||
| 51 | static bool li_alarm = false; | ||
| 52 | 53 | ||
| 53 | typedef struct { | 54 | typedef struct { |
| 54 | int errorcode; | 55 | int errorcode; |
| @@ -198,9 +199,7 @@ void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_ | |||
| 198 | * positive value means a success retrieving the value. | 199 | * positive value means a success retrieving the value. |
| 199 | * - status is set to WARNING if there's no sync.peer (otherwise OK) and is | 200 | * - status is set to WARNING if there's no sync.peer (otherwise OK) and is |
| 200 | * the return value of the function. | 201 | * the return value of the function. |
| 201 | * status is pretty much useless as syncsource_found is a global variable | 202 | */ |
| 202 | * used later in main to check is the server was synchronized. It works | ||
| 203 | * so I left it alone */ | ||
| 204 | typedef struct { | 203 | typedef struct { |
| 205 | mp_state_enum state; | 204 | mp_state_enum state; |
| 206 | mp_state_enum offset_result; | 205 | mp_state_enum offset_result; |
| @@ -208,6 +207,8 @@ typedef struct { | |||
| 208 | double jitter; | 207 | double jitter; |
| 209 | long stratum; | 208 | long stratum; |
| 210 | int num_truechimers; | 209 | int num_truechimers; |
| 210 | bool syncsource_found; | ||
| 211 | bool li_alarm; | ||
| 211 | } ntp_request_result; | 212 | } ntp_request_result; |
| 212 | ntp_request_result ntp_request(const check_ntp_peer_config config) { | 213 | ntp_request_result ntp_request(const check_ntp_peer_config config) { |
| 213 | 214 | ||
| @@ -217,6 +218,8 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) { | |||
| 217 | .jitter = -1, | 218 | .jitter = -1, |
| 218 | .stratum = -1, | 219 | .stratum = -1, |
| 219 | .num_truechimers = 0, | 220 | .num_truechimers = 0, |
| 221 | .syncsource_found = false, | ||
| 222 | .li_alarm = false, | ||
| 220 | }; | 223 | }; |
| 221 | 224 | ||
| 222 | /* Long-winded explanation: | 225 | /* Long-winded explanation: |
| @@ -235,19 +238,16 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) { | |||
| 235 | * 4) Extract the offset, jitter and stratum value from the data[] | 238 | * 4) Extract the offset, jitter and stratum value from the data[] |
| 236 | * (it's ASCII) | 239 | * (it's ASCII) |
| 237 | */ | 240 | */ |
| 238 | int min_peer_sel = PEER_INCLUDED; | ||
| 239 | int num_candidates = 0; | ||
| 240 | void *tmp; | ||
| 241 | ntp_assoc_status_pair *peers = NULL; | ||
| 242 | int peer_offset = 0; | ||
| 243 | size_t peers_size = 0; | ||
| 244 | size_t npeers = 0; | ||
| 245 | int conn = -1; | 241 | int conn = -1; |
| 246 | my_udp_connect(config.server_address, config.port, &conn); | 242 | my_udp_connect(config.server_address, config.port, &conn); |
| 247 | 243 | ||
| 248 | /* keep sending requests until the server stops setting the | 244 | /* keep sending requests until the server stops setting the |
| 249 | * REM_MORE bit, though usually this is only 1 packet. */ | 245 | * REM_MORE bit, though usually this is only 1 packet. */ |
| 250 | ntp_control_message req; | 246 | ntp_control_message req; |
| 247 | ntp_assoc_status_pair *peers = NULL; | ||
| 248 | int peer_offset = 0; | ||
| 249 | size_t peers_size = 0; | ||
| 250 | size_t npeers = 0; | ||
| 251 | do { | 251 | do { |
| 252 | setup_control_request(&req, OP_READSTAT, 1); | 252 | setup_control_request(&req, OP_READSTAT, 1); |
| 253 | DBG(printf("sending READSTAT request")); | 253 | DBG(printf("sending READSTAT request")); |
| @@ -269,12 +269,13 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) { | |||
| 269 | } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1)); | 269 | } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1)); |
| 270 | 270 | ||
| 271 | if (LI(req.flags) == LI_ALARM) { | 271 | if (LI(req.flags) == LI_ALARM) { |
| 272 | li_alarm = true; | 272 | result.li_alarm = true; |
| 273 | } | 273 | } |
| 274 | /* Each peer identifier is 4 bytes in the data section, which | 274 | /* Each peer identifier is 4 bytes in the data section, which |
| 275 | * we represent as a ntp_assoc_status_pair datatype. | 275 | * we represent as a ntp_assoc_status_pair datatype. |
| 276 | */ | 276 | */ |
| 277 | peers_size += ntohs(req.count); | 277 | peers_size += ntohs(req.count); |
| 278 | void *tmp; | ||
| 278 | if ((tmp = realloc(peers, peers_size)) == NULL) { | 279 | if ((tmp = realloc(peers, peers_size)) == NULL) { |
| 279 | free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); | 280 | free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); |
| 280 | } | 281 | } |
| @@ -287,13 +288,15 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) { | |||
| 287 | /* first, let's find out if we have a sync source, or if there are | 288 | /* first, let's find out if we have a sync source, or if there are |
| 288 | * at least some candidates. In the latter case we'll issue | 289 | * at least some candidates. In the latter case we'll issue |
| 289 | * a warning but go ahead with the check on them. */ | 290 | * a warning but go ahead with the check on them. */ |
| 291 | int min_peer_sel = PEER_INCLUDED; | ||
| 292 | int num_candidates = 0; | ||
| 290 | for (size_t i = 0; i < npeers; i++) { | 293 | for (size_t i = 0; i < npeers; i++) { |
| 291 | if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) { | 294 | if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) { |
| 292 | result.num_truechimers++; | 295 | result.num_truechimers++; |
| 293 | if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) { | 296 | if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) { |
| 294 | num_candidates++; | 297 | num_candidates++; |
| 295 | if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) { | 298 | if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) { |
| 296 | syncsource_found = true; | 299 | result.syncsource_found = true; |
| 297 | min_peer_sel = PEER_SYNCSOURCE; | 300 | min_peer_sel = PEER_SYNCSOURCE; |
| 298 | } | 301 | } |
| 299 | } | 302 | } |
| @@ -302,18 +305,18 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) { | |||
| 302 | 305 | ||
| 303 | if (verbose) { | 306 | if (verbose) { |
| 304 | printf("%d candidate peers available\n", num_candidates); | 307 | printf("%d candidate peers available\n", num_candidates); |
| 305 | } | 308 | if (result.syncsource_found) { |
| 306 | if (verbose && syncsource_found) { | 309 | printf("synchronization source found\n"); |
| 307 | printf("synchronization source found\n"); | 310 | } |
| 308 | } | 311 | } |
| 309 | 312 | ||
| 310 | if (!syncsource_found) { | 313 | if (!result.syncsource_found) { |
| 311 | result.state = STATE_WARNING; | 314 | result.state = STATE_WARNING; |
| 312 | if (verbose) { | 315 | if (verbose) { |
| 313 | printf("warning: no synchronization source found\n"); | 316 | printf("warning: no synchronization source found\n"); |
| 314 | } | 317 | } |
| 315 | } | 318 | } |
| 316 | if (li_alarm) { | 319 | if (result.li_alarm) { |
| 317 | result.state = STATE_WARNING; | 320 | result.state = STATE_WARNING; |
| 318 | if (verbose) { | 321 | if (verbose) { |
| 319 | printf("warning: LI_ALARM bit is set\n"); | 322 | printf("warning: LI_ALARM bit is set\n"); |
| @@ -329,7 +332,7 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) { | |||
| 329 | if (verbose) { | 332 | if (verbose) { |
| 330 | printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); | 333 | printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); |
| 331 | } | 334 | } |
| 332 | xasprintf(&data, ""); | 335 | data = strdup(""); |
| 333 | do { | 336 | do { |
| 334 | setup_control_request(&req, OP_READVAR, 2); | 337 | setup_control_request(&req, OP_READVAR, 2); |
| 335 | req.assoc = peers[i].assoc; | 338 | req.assoc = peers[i].assoc; |
| @@ -475,16 +478,30 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) { | |||
| 475 | } | 478 | } |
| 476 | 479 | ||
| 477 | check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) { | 480 | check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) { |
| 478 | static struct option longopts[] = { | 481 | |
| 479 | {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, | 482 | enum { |
| 480 | {"verbose", no_argument, 0, 'v'}, {"use-ipv4", no_argument, 0, '4'}, | 483 | output_format_index = CHAR_MAX + 1, |
| 481 | {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'}, | 484 | }; |
| 482 | {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, | 485 | |
| 483 | {"swarn", required_argument, 0, 'W'}, {"scrit", required_argument, 0, 'C'}, | 486 | static struct option longopts[] = {{"version", no_argument, 0, 'V'}, |
| 484 | {"jwarn", required_argument, 0, 'j'}, {"jcrit", required_argument, 0, 'k'}, | 487 | {"help", no_argument, 0, 'h'}, |
| 485 | {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, | 488 | {"verbose", no_argument, 0, 'v'}, |
| 486 | {"timeout", required_argument, 0, 't'}, {"hostname", required_argument, 0, 'H'}, | 489 | {"use-ipv4", no_argument, 0, '4'}, |
| 487 | {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}}; | 490 | {"use-ipv6", no_argument, 0, '6'}, |
| 491 | {"quiet", no_argument, 0, 'q'}, | ||
| 492 | {"warning", required_argument, 0, 'w'}, | ||
| 493 | {"critical", required_argument, 0, 'c'}, | ||
| 494 | {"swarn", required_argument, 0, 'W'}, | ||
| 495 | {"scrit", required_argument, 0, 'C'}, | ||
| 496 | {"jwarn", required_argument, 0, 'j'}, | ||
| 497 | {"jcrit", required_argument, 0, 'k'}, | ||
| 498 | {"twarn", required_argument, 0, 'm'}, | ||
| 499 | {"tcrit", required_argument, 0, 'n'}, | ||
| 500 | {"timeout", required_argument, 0, 't'}, | ||
| 501 | {"hostname", required_argument, 0, 'H'}, | ||
| 502 | {"port", required_argument, 0, 'p'}, | ||
| 503 | {"output-format", required_argument, 0, output_format_index}, | ||
| 504 | {0, 0, 0, 0}}; | ||
| 488 | 505 | ||
| 489 | if (argc < 2) { | 506 | if (argc < 2) { |
| 490 | usage("\n"); | 507 | usage("\n"); |
| @@ -504,6 +521,17 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) { | |||
| 504 | } | 521 | } |
| 505 | 522 | ||
| 506 | switch (option_char) { | 523 | switch (option_char) { |
| 524 | case output_format_index: { | ||
| 525 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 526 | if (!parser.parsing_success) { | ||
| 527 | printf("Invalid output format: %s\n", optarg); | ||
| 528 | exit(STATE_UNKNOWN); | ||
| 529 | } | ||
| 530 | |||
| 531 | result.config.output_format_is_set = true; | ||
| 532 | result.config.output_format = parser.output_format; | ||
| 533 | break; | ||
| 534 | } | ||
| 507 | case 'h': | 535 | case 'h': |
| 508 | print_help(); | 536 | print_help(); |
| 509 | exit(STATE_UNKNOWN); | 537 | exit(STATE_UNKNOWN); |
| @@ -518,36 +546,84 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) { | |||
| 518 | case 'q': | 546 | case 'q': |
| 519 | result.config.quiet = true; | 547 | result.config.quiet = true; |
| 520 | break; | 548 | break; |
| 521 | case 'w': | 549 | case 'w': { |
| 522 | result.config.owarn = optarg; | 550 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 523 | break; | 551 | if (tmp.error != MP_PARSING_SUCCES) { |
| 524 | case 'c': | 552 | die(STATE_UNKNOWN, "failed to parse warning offset threshold"); |
| 525 | result.config.ocrit = optarg; | 553 | } |
| 526 | break; | 554 | |
| 527 | case 'W': | 555 | result.config.offset_thresholds = |
| 556 | mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range); | ||
| 557 | } break; | ||
| 558 | case 'c': { | ||
| 559 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 560 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 561 | die(STATE_UNKNOWN, "failed to parse critical offset threshold"); | ||
| 562 | } | ||
| 563 | |||
| 564 | result.config.offset_thresholds = | ||
| 565 | mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range); | ||
| 566 | } break; | ||
| 567 | case 'W': { | ||
| 528 | result.config.do_stratum = true; | 568 | result.config.do_stratum = true; |
| 529 | result.config.swarn = optarg; | 569 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 530 | break; | 570 | if (tmp.error != MP_PARSING_SUCCES) { |
| 531 | case 'C': | 571 | die(STATE_UNKNOWN, "failed to parse warning stratum threshold"); |
| 572 | } | ||
| 573 | |||
| 574 | result.config.stratum_thresholds = | ||
| 575 | mp_thresholds_set_warn(result.config.stratum_thresholds, tmp.range); | ||
| 576 | } break; | ||
| 577 | case 'C': { | ||
| 532 | result.config.do_stratum = true; | 578 | result.config.do_stratum = true; |
| 533 | result.config.scrit = optarg; | 579 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 534 | break; | 580 | if (tmp.error != MP_PARSING_SUCCES) { |
| 535 | case 'j': | 581 | die(STATE_UNKNOWN, "failed to parse critical stratum threshold"); |
| 582 | } | ||
| 583 | |||
| 584 | result.config.stratum_thresholds = | ||
| 585 | mp_thresholds_set_crit(result.config.stratum_thresholds, tmp.range); | ||
| 586 | } break; | ||
| 587 | case 'j': { | ||
| 536 | result.config.do_jitter = true; | 588 | result.config.do_jitter = true; |
| 537 | result.config.jwarn = optarg; | 589 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 538 | break; | 590 | if (tmp.error != MP_PARSING_SUCCES) { |
| 539 | case 'k': | 591 | die(STATE_UNKNOWN, "failed to parse warning jitter threshold"); |
| 592 | } | ||
| 593 | |||
| 594 | result.config.jitter_thresholds = | ||
| 595 | mp_thresholds_set_warn(result.config.jitter_thresholds, tmp.range); | ||
| 596 | } break; | ||
| 597 | case 'k': { | ||
| 540 | result.config.do_jitter = true; | 598 | result.config.do_jitter = true; |
| 541 | result.config.jcrit = optarg; | 599 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 542 | break; | 600 | if (tmp.error != MP_PARSING_SUCCES) { |
| 543 | case 'm': | 601 | die(STATE_UNKNOWN, "failed to parse critical jitter threshold"); |
| 602 | } | ||
| 603 | |||
| 604 | result.config.jitter_thresholds = | ||
| 605 | mp_thresholds_set_crit(result.config.jitter_thresholds, tmp.range); | ||
| 606 | } break; | ||
| 607 | case 'm': { | ||
| 544 | result.config.do_truechimers = true; | 608 | result.config.do_truechimers = true; |
| 545 | result.config.twarn = optarg; | 609 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 546 | break; | 610 | if (tmp.error != MP_PARSING_SUCCES) { |
| 547 | case 'n': | 611 | die(STATE_UNKNOWN, "failed to parse warning truechimer threshold"); |
| 612 | } | ||
| 613 | |||
| 614 | result.config.truechimer_thresholds = | ||
| 615 | mp_thresholds_set_warn(result.config.truechimer_thresholds, tmp.range); | ||
| 616 | } break; | ||
| 617 | case 'n': { | ||
| 548 | result.config.do_truechimers = true; | 618 | result.config.do_truechimers = true; |
| 549 | result.config.tcrit = optarg; | 619 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 550 | break; | 620 | if (tmp.error != MP_PARSING_SUCCES) { |
| 621 | die(STATE_UNKNOWN, "failed to parse critical truechimer threshold"); | ||
| 622 | } | ||
| 623 | |||
| 624 | result.config.truechimer_thresholds = | ||
| 625 | mp_thresholds_set_crit(result.config.truechimer_thresholds, tmp.range); | ||
| 626 | } break; | ||
| 551 | case 'H': | 627 | case 'H': |
| 552 | if (!is_host(optarg)) { | 628 | if (!is_host(optarg)) { |
| 553 | usage2(_("Invalid hostname/address"), optarg); | 629 | usage2(_("Invalid hostname/address"), optarg); |
| @@ -581,11 +657,6 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) { | |||
| 581 | usage4(_("Hostname was not supplied")); | 657 | usage4(_("Hostname was not supplied")); |
| 582 | } | 658 | } |
| 583 | 659 | ||
| 584 | set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit); | ||
| 585 | set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit); | ||
| 586 | set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit); | ||
| 587 | set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit); | ||
| 588 | |||
| 589 | return result; | 660 | return result; |
| 590 | } | 661 | } |
| 591 | 662 | ||
| @@ -627,6 +698,10 @@ int main(int argc, char *argv[]) { | |||
| 627 | 698 | ||
| 628 | const check_ntp_peer_config config = tmp_config.config; | 699 | const check_ntp_peer_config config = tmp_config.config; |
| 629 | 700 | ||
| 701 | if (config.output_format_is_set) { | ||
| 702 | mp_set_format(config.output_format); | ||
| 703 | } | ||
| 704 | |||
| 630 | /* initialize alarm signal handling */ | 705 | /* initialize alarm signal handling */ |
| 631 | signal(SIGALRM, socket_timeout_alarm_handler); | 706 | signal(SIGALRM, socket_timeout_alarm_handler); |
| 632 | 707 | ||
| @@ -634,125 +709,113 @@ int main(int argc, char *argv[]) { | |||
| 634 | alarm(socket_timeout); | 709 | alarm(socket_timeout); |
| 635 | 710 | ||
| 636 | /* This returns either OK or WARNING (See comment preceding ntp_request) */ | 711 | /* This returns either OK or WARNING (See comment preceding ntp_request) */ |
| 637 | ntp_request_result ntp_res = ntp_request(config); | 712 | const ntp_request_result ntp_res = ntp_request(config); |
| 638 | mp_state_enum result = STATE_UNKNOWN; | 713 | mp_check overall = mp_check_init(); |
| 639 | 714 | ||
| 715 | mp_subcheck sc_offset = mp_subcheck_init(); | ||
| 716 | xasprintf(&sc_offset.output, "offset"); | ||
| 640 | if (ntp_res.offset_result == STATE_UNKNOWN) { | 717 | if (ntp_res.offset_result == STATE_UNKNOWN) { |
| 641 | /* if there's no sync peer (this overrides ntp_request output): */ | 718 | /* if there's no sync peer (this overrides ntp_request output): */ |
| 642 | result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL); | 719 | sc_offset = |
| 720 | mp_set_subcheck_state(sc_offset, (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL)); | ||
| 721 | xasprintf(&sc_offset.output, "%s unknown", sc_offset.output); | ||
| 643 | } else { | 722 | } else { |
| 644 | /* Be quiet if there's no candidates either */ | 723 | /* Be quiet if there's no candidates either */ |
| 645 | if (config.quiet && result == STATE_WARNING) { | 724 | mp_state_enum tmp = STATE_OK; |
| 646 | result = STATE_UNKNOWN; | 725 | if (config.quiet && ntp_res.state == STATE_WARNING) { |
| 726 | tmp = STATE_UNKNOWN; | ||
| 647 | } | 727 | } |
| 648 | result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds)); | 728 | |
| 729 | xasprintf(&sc_offset.output, "%s: %.6fs", sc_offset.output, ntp_res.offset); | ||
| 730 | |||
| 731 | mp_perfdata pd_offset = perfdata_init(); | ||
| 732 | pd_offset.value = mp_create_pd_value(fabs(ntp_res.offset)); | ||
| 733 | pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds); | ||
| 734 | pd_offset.label = "offset"; | ||
| 735 | pd_offset.uom = "s"; | ||
| 736 | mp_add_perfdata_to_subcheck(&sc_offset, pd_offset); | ||
| 737 | |||
| 738 | tmp = max_state_alt(tmp, mp_get_pd_status(pd_offset)); | ||
| 739 | sc_offset = mp_set_subcheck_state(sc_offset, tmp); | ||
| 649 | } | 740 | } |
| 650 | 741 | ||
| 651 | mp_state_enum oresult = result; | 742 | mp_add_subcheck_to_check(&overall, sc_offset); |
| 652 | mp_state_enum tresult = STATE_UNKNOWN; | ||
| 653 | 743 | ||
| 744 | // truechimers | ||
| 654 | if (config.do_truechimers) { | 745 | if (config.do_truechimers) { |
| 655 | tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds); | 746 | mp_subcheck sc_truechimers = mp_subcheck_init(); |
| 656 | result = max_state_alt(result, tresult); | 747 | xasprintf(&sc_truechimers.output, "truechimers: %i", ntp_res.num_truechimers); |
| 657 | } | ||
| 658 | 748 | ||
| 659 | mp_state_enum sresult = STATE_UNKNOWN; | 749 | mp_perfdata pd_truechimers = perfdata_init(); |
| 750 | pd_truechimers.value = mp_create_pd_value(ntp_res.num_truechimers); | ||
| 751 | pd_truechimers.label = "truechimers"; | ||
| 752 | pd_truechimers = mp_pd_set_thresholds(pd_truechimers, config.truechimer_thresholds); | ||
| 660 | 753 | ||
| 661 | if (config.do_stratum) { | 754 | mp_add_perfdata_to_subcheck(&sc_truechimers, pd_truechimers); |
| 662 | sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds); | ||
| 663 | result = max_state_alt(result, sresult); | ||
| 664 | } | ||
| 665 | 755 | ||
| 666 | mp_state_enum jresult = STATE_UNKNOWN; | 756 | sc_truechimers = mp_set_subcheck_state(sc_truechimers, mp_get_pd_status(pd_truechimers)); |
| 667 | 757 | ||
| 668 | if (config.do_jitter) { | 758 | mp_add_subcheck_to_check(&overall, sc_truechimers); |
| 669 | jresult = get_status(ntp_res.jitter, config.jitter_thresholds); | ||
| 670 | result = max_state_alt(result, jresult); | ||
| 671 | } | 759 | } |
| 672 | 760 | ||
| 673 | char *result_line; | 761 | if (config.do_stratum) { |
| 674 | switch (result) { | 762 | mp_subcheck sc_stratum = mp_subcheck_init(); |
| 675 | case STATE_CRITICAL: | 763 | xasprintf(&sc_stratum.output, "stratum: %li", ntp_res.stratum); |
| 676 | xasprintf(&result_line, _("NTP CRITICAL:")); | ||
| 677 | break; | ||
| 678 | case STATE_WARNING: | ||
| 679 | xasprintf(&result_line, _("NTP WARNING:")); | ||
| 680 | break; | ||
| 681 | case STATE_OK: | ||
| 682 | xasprintf(&result_line, _("NTP OK:")); | ||
| 683 | break; | ||
| 684 | default: | ||
| 685 | xasprintf(&result_line, _("NTP UNKNOWN:")); | ||
| 686 | break; | ||
| 687 | } | ||
| 688 | 764 | ||
| 689 | if (!syncsource_found) { | 765 | mp_perfdata pd_stratum = perfdata_init(); |
| 690 | xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized")); | 766 | pd_stratum.value = mp_create_pd_value(ntp_res.stratum); |
| 691 | } else if (li_alarm) { | 767 | pd_stratum = mp_pd_set_thresholds(pd_stratum, config.stratum_thresholds); |
| 692 | xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set")); | 768 | pd_stratum.label = "stratum"; |
| 693 | } | ||
| 694 | 769 | ||
| 695 | char *perfdata_line; | 770 | mp_add_perfdata_to_subcheck(&sc_stratum, pd_stratum); |
| 696 | if (ntp_res.offset_result == STATE_UNKNOWN) { | 771 | |
| 697 | xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); | 772 | sc_stratum = mp_set_subcheck_state(sc_stratum, mp_get_pd_status(pd_stratum)); |
| 698 | xasprintf(&perfdata_line, ""); | 773 | |
| 699 | } else if (oresult == STATE_WARNING) { | 774 | mp_add_subcheck_to_check(&overall, sc_stratum); |
| 700 | xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), | ||
| 701 | ntp_res.offset); | ||
| 702 | } else if (oresult == STATE_CRITICAL) { | ||
| 703 | xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), | ||
| 704 | ntp_res.offset); | ||
| 705 | } else { | ||
| 706 | xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset); | ||
| 707 | } | 775 | } |
| 708 | xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds)); | ||
| 709 | 776 | ||
| 710 | if (config.do_jitter) { | 777 | if (config.do_jitter) { |
| 711 | if (jresult == STATE_WARNING) { | 778 | mp_subcheck sc_jitter = mp_subcheck_init(); |
| 712 | xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter); | 779 | xasprintf(&sc_jitter.output, "jitter: %f", ntp_res.jitter); |
| 713 | } else if (jresult == STATE_CRITICAL) { | ||
| 714 | xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter); | ||
| 715 | } else { | ||
| 716 | xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter); | ||
| 717 | } | ||
| 718 | xasprintf(&perfdata_line, "%s %s", perfdata_line, | ||
| 719 | perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds)); | ||
| 720 | } | ||
| 721 | 780 | ||
| 722 | if (config.do_stratum) { | 781 | mp_perfdata pd_jitter = perfdata_init(); |
| 723 | if (sresult == STATE_WARNING) { | 782 | pd_jitter.value = mp_create_pd_value(ntp_res.jitter); |
| 724 | xasprintf(&result_line, "%s, stratum=%li (WARNING)", result_line, ntp_res.stratum); | 783 | pd_jitter = mp_pd_set_thresholds(pd_jitter, config.jitter_thresholds); |
| 725 | } else if (sresult == STATE_CRITICAL) { | 784 | pd_jitter.label = "jitter"; |
| 726 | xasprintf(&result_line, "%s, stratum=%li (CRITICAL)", result_line, ntp_res.stratum); | 785 | |
| 727 | } else { | 786 | mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter); |
| 728 | xasprintf(&result_line, "%s, stratum=%li", result_line, ntp_res.stratum); | 787 | |
| 729 | } | 788 | sc_jitter = mp_set_subcheck_state(sc_jitter, mp_get_pd_status(pd_jitter)); |
| 730 | xasprintf(&perfdata_line, "%s %s", perfdata_line, | 789 | mp_add_subcheck_to_check(&overall, sc_jitter); |
| 731 | perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds)); | ||
| 732 | } | 790 | } |
| 733 | 791 | ||
| 734 | if (config.do_truechimers) { | 792 | mp_subcheck sc_other_info = mp_subcheck_init(); |
| 735 | if (tresult == STATE_WARNING) { | 793 | sc_other_info = mp_set_subcheck_default_state(sc_other_info, STATE_OK); |
| 736 | xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, | 794 | if (!ntp_res.syncsource_found) { |
| 737 | ntp_res.num_truechimers); | 795 | xasprintf(&sc_other_info.output, "%s", _("Server not synchronized")); |
| 738 | } else if (tresult == STATE_CRITICAL) { | 796 | mp_add_subcheck_to_check(&overall, sc_other_info); |
| 739 | xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, | 797 | } else if (ntp_res.li_alarm) { |
| 740 | ntp_res.num_truechimers); | 798 | xasprintf(&sc_other_info.output, "%s", _("Server has the LI_ALARM bit set")); |
| 741 | } else { | 799 | mp_add_subcheck_to_check(&overall, sc_other_info); |
| 742 | xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers); | ||
| 743 | } | ||
| 744 | xasprintf(&perfdata_line, "%s %s", perfdata_line, | ||
| 745 | perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers, | ||
| 746 | config.truechimer_thresholds)); | ||
| 747 | } | 800 | } |
| 748 | 801 | ||
| 749 | printf("%s|%s\n", result_line, perfdata_line); | 802 | { |
| 803 | mp_subcheck sc_offset = mp_subcheck_init(); | ||
| 804 | sc_offset = mp_set_subcheck_default_state(sc_offset, STATE_OK); | ||
| 805 | xasprintf(&sc_offset.output, "offset: %.10gs", ntp_res.offset); | ||
| 806 | |||
| 807 | mp_perfdata pd_offset = perfdata_init(); | ||
| 808 | pd_offset.value = mp_create_pd_value(ntp_res.offset); | ||
| 809 | pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds); | ||
| 810 | |||
| 811 | sc_offset = mp_set_subcheck_state(sc_offset, ntp_res.offset_result); | ||
| 812 | } | ||
| 750 | 813 | ||
| 751 | if (config.server_address != NULL) { | 814 | if (config.server_address != NULL) { |
| 752 | free(config.server_address); | 815 | free(config.server_address); |
| 753 | } | 816 | } |
| 754 | 817 | ||
| 755 | exit(result); | 818 | mp_exit(overall); |
| 756 | } | 819 | } |
| 757 | 820 | ||
| 758 | void print_help(void) { | 821 | void print_help(void) { |
| @@ -791,6 +854,7 @@ void print_help(void) { | |||
| 791 | printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")")); | 854 | printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")")); |
| 792 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 855 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
| 793 | printf(UT_VERBOSE); | 856 | printf(UT_VERBOSE); |
| 857 | printf(UT_OUTPUT_FORMAT); | ||
| 794 | 858 | ||
| 795 | printf("\n"); | 859 | printf("\n"); |
| 796 | printf("%s\n", _("This plugin checks an NTP server independent of any commandline")); | 860 | printf("%s\n", _("This plugin checks an NTP server independent of any commandline")); |
diff --git a/plugins/check_ntp_peer.d/config.h b/plugins/check_ntp_peer.d/config.h index 00e6b05d..488d936c 100644 --- a/plugins/check_ntp_peer.d/config.h +++ b/plugins/check_ntp_peer.d/config.h | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 5 | #include "perfdata.h" | ||
| 4 | #include "thresholds.h" | 6 | #include "thresholds.h" |
| 5 | #include <stddef.h> | 7 | #include <stddef.h> |
| 6 | 8 | ||
| @@ -16,26 +18,21 @@ typedef struct { | |||
| 16 | 18 | ||
| 17 | // truechimer stuff | 19 | // truechimer stuff |
| 18 | bool do_truechimers; | 20 | bool do_truechimers; |
| 19 | char *twarn; | 21 | mp_thresholds truechimer_thresholds; |
| 20 | char *tcrit; | ||
| 21 | thresholds *truechimer_thresholds; | ||
| 22 | 22 | ||
| 23 | char *owarn; | 23 | // offset thresholds |
| 24 | char *ocrit; | 24 | mp_thresholds offset_thresholds; |
| 25 | thresholds *offset_thresholds; | ||
| 26 | 25 | ||
| 27 | // stratum stuff | 26 | // stratum stuff |
| 28 | bool do_stratum; | 27 | bool do_stratum; |
| 29 | char *swarn; | 28 | mp_thresholds stratum_thresholds; |
| 30 | char *scrit; | ||
| 31 | thresholds *stratum_thresholds; | ||
| 32 | 29 | ||
| 33 | // jitter stuff | 30 | // jitter stuff |
| 34 | bool do_jitter; | 31 | bool do_jitter; |
| 35 | char *jwarn; | 32 | mp_thresholds jitter_thresholds; |
| 36 | char *jcrit; | ||
| 37 | thresholds *jitter_thresholds; | ||
| 38 | 33 | ||
| 34 | bool output_format_is_set; | ||
| 35 | mp_output_format output_format; | ||
| 39 | } check_ntp_peer_config; | 36 | } check_ntp_peer_config; |
| 40 | 37 | ||
| 41 | check_ntp_peer_config check_ntp_peer_config_init() { | 38 | check_ntp_peer_config check_ntp_peer_config_init() { |
| @@ -45,23 +42,41 @@ check_ntp_peer_config check_ntp_peer_config_init() { | |||
| 45 | 42 | ||
| 46 | .quiet = false, | 43 | .quiet = false, |
| 47 | .do_truechimers = false, | 44 | .do_truechimers = false, |
| 48 | .twarn = "0:", | 45 | .truechimer_thresholds = mp_thresholds_init(), |
| 49 | .tcrit = "0:", | ||
| 50 | .truechimer_thresholds = NULL, | ||
| 51 | 46 | ||
| 52 | .owarn = "60", | 47 | .offset_thresholds = mp_thresholds_init(), |
| 53 | .ocrit = "120", | ||
| 54 | .offset_thresholds = NULL, | ||
| 55 | 48 | ||
| 56 | .do_stratum = false, | 49 | .do_stratum = false, |
| 57 | .swarn = "-1:16", | 50 | .stratum_thresholds = mp_thresholds_init(), |
| 58 | .scrit = "-1:16", | ||
| 59 | .stratum_thresholds = NULL, | ||
| 60 | 51 | ||
| 61 | .do_jitter = false, | 52 | .do_jitter = false, |
| 62 | .jwarn = "-1:5000", | 53 | .jitter_thresholds = mp_thresholds_init(), |
| 63 | .jcrit = "-1:10000", | 54 | |
| 64 | .jitter_thresholds = NULL, | 55 | .output_format_is_set = false, |
| 65 | }; | 56 | }; |
| 57 | |||
| 58 | mp_range stratum_default = mp_range_init(); | ||
| 59 | stratum_default = mp_range_set_start(stratum_default, mp_create_pd_value(-1)); | ||
| 60 | stratum_default = mp_range_set_end(stratum_default, mp_create_pd_value(16)); | ||
| 61 | tmp.stratum_thresholds = mp_thresholds_set_warn(tmp.stratum_thresholds, stratum_default); | ||
| 62 | tmp.stratum_thresholds = mp_thresholds_set_crit(tmp.stratum_thresholds, stratum_default); | ||
| 63 | |||
| 64 | mp_range jitter_w_default = mp_range_init(); | ||
| 65 | jitter_w_default = mp_range_set_start(jitter_w_default, mp_create_pd_value(-1)); | ||
| 66 | jitter_w_default = mp_range_set_end(jitter_w_default, mp_create_pd_value(5000)); | ||
| 67 | tmp.jitter_thresholds = mp_thresholds_set_warn(tmp.jitter_thresholds, jitter_w_default); | ||
| 68 | |||
| 69 | mp_range jitter_c_default = mp_range_init(); | ||
| 70 | jitter_c_default = mp_range_set_start(jitter_c_default, mp_create_pd_value(-1)); | ||
| 71 | jitter_c_default = mp_range_set_end(jitter_c_default, mp_create_pd_value(10000)); | ||
| 72 | tmp.jitter_thresholds = mp_thresholds_set_crit(tmp.jitter_thresholds, jitter_c_default); | ||
| 73 | |||
| 74 | mp_range offset_w_default = mp_range_init(); | ||
| 75 | offset_w_default = mp_range_set_end(offset_w_default, mp_create_pd_value(60)); | ||
| 76 | tmp.offset_thresholds = mp_thresholds_set_warn(tmp.offset_thresholds, offset_w_default); | ||
| 77 | |||
| 78 | mp_range offset_c_default = mp_range_init(); | ||
| 79 | offset_c_default = mp_range_set_end(offset_c_default, mp_create_pd_value(120)); | ||
| 80 | tmp.offset_thresholds = mp_thresholds_set_crit(tmp.offset_thresholds, offset_c_default); | ||
| 66 | return tmp; | 81 | return tmp; |
| 67 | } | 82 | } |
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index ad69b804..602b6010 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c | |||
| @@ -34,12 +34,10 @@ | |||
| 34 | * | 34 | * |
| 35 | *****************************************************************************/ | 35 | *****************************************************************************/ |
| 36 | 36 | ||
| 37 | const char *progname = "check_ntp_time"; | 37 | #include "output.h" |
| 38 | const char *copyright = "2006-2024"; | ||
| 39 | const char *email = "devel@monitoring-plugins.org"; | ||
| 40 | |||
| 41 | #include "common.h" | 38 | #include "common.h" |
| 42 | #include "netutils.h" | 39 | #include "netutils.h" |
| 40 | #include "perfdata.h" | ||
| 43 | #include "utils.h" | 41 | #include "utils.h" |
| 44 | #include "states.h" | 42 | #include "states.h" |
| 45 | #include "thresholds.h" | 43 | #include "thresholds.h" |
| @@ -47,6 +45,10 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 47 | 45 | ||
| 48 | static int verbose = 0; | 46 | static int verbose = 0; |
| 49 | 47 | ||
| 48 | const char *progname = "check_ntp_time"; | ||
| 49 | const char *copyright = "2006-2024"; | ||
| 50 | const char *email = "devel@monitoring-plugins.org"; | ||
| 51 | |||
| 50 | typedef struct { | 52 | typedef struct { |
| 51 | int errorcode; | 53 | int errorcode; |
| 52 | check_ntp_time_config config; | 54 | check_ntp_time_config config; |
| @@ -61,9 +63,6 @@ void print_usage(void); | |||
| 61 | # define AVG_NUM 4 | 63 | # define AVG_NUM 4 |
| 62 | #endif | 64 | #endif |
| 63 | 65 | ||
| 64 | /* max size of control message data */ | ||
| 65 | #define MAX_CM_SIZE 468 | ||
| 66 | |||
| 67 | /* this structure holds everything in an ntp request/response as per rfc1305 */ | 66 | /* this structure holds everything in an ntp request/response as per rfc1305 */ |
| 68 | typedef struct { | 67 | typedef struct { |
| 69 | uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ | 68 | uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ |
| @@ -169,7 +168,9 @@ typedef struct { | |||
| 169 | : 0) | 168 | : 0) |
| 170 | 169 | ||
| 171 | /* convert a struct timeval to a double */ | 170 | /* convert a struct timeval to a double */ |
| 172 | #define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec)) | 171 | static double TVasDOUBLE(struct timeval time) { |
| 172 | return ((double)time.tv_sec + (0.000001 * (double)time.tv_usec)); | ||
| 173 | } | ||
| 173 | 174 | ||
| 174 | /* convert an ntp 64-bit fp number to a struct timeval */ | 175 | /* convert an ntp 64-bit fp number to a struct timeval */ |
| 175 | #define NTP64toTV(n, t) \ | 176 | #define NTP64toTV(n, t) \ |
| @@ -262,8 +263,8 @@ void setup_request(ntp_message *message) { | |||
| 262 | /* select the "best" server from a list of servers, and return its index. | 263 | /* select the "best" server from a list of servers, and return its index. |
| 263 | * this is done by filtering servers based on stratum, dispersion, and | 264 | * this is done by filtering servers based on stratum, dispersion, and |
| 264 | * finally round-trip delay. */ | 265 | * finally round-trip delay. */ |
| 265 | int best_offset_server(const ntp_server_results *slist, int nservers) { | 266 | static int best_offset_server(const ntp_server_results *slist, int nservers) { |
| 266 | int best_server = -1; | 267 | int best_server_index = -1; |
| 267 | 268 | ||
| 268 | /* for each server */ | 269 | /* for each server */ |
| 269 | for (int cserver = 0; cserver < nservers; cserver++) { | 270 | for (int cserver = 0; cserver < nservers; cserver++) { |
| @@ -286,33 +287,33 @@ int best_offset_server(const ntp_server_results *slist, int nservers) { | |||
| 286 | } | 287 | } |
| 287 | 288 | ||
| 288 | /* If we don't have a server yet, use the first one */ | 289 | /* If we don't have a server yet, use the first one */ |
| 289 | if (best_server == -1) { | 290 | if (best_server_index == -1) { |
| 290 | best_server = cserver; | 291 | best_server_index = cserver; |
| 291 | DBG(printf("using peer %d as our first candidate\n", best_server)); | 292 | DBG(printf("using peer %d as our first candidate\n", best_server_index)); |
| 292 | continue; | 293 | continue; |
| 293 | } | 294 | } |
| 294 | 295 | ||
| 295 | /* compare the server to the best one we've seen so far */ | 296 | /* compare the server to the best one we've seen so far */ |
| 296 | /* does it have an equal or better stratum? */ | 297 | /* does it have an equal or better stratum? */ |
| 297 | DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); | 298 | DBG(printf("comparing peer %d with peer %d\n", cserver, best_server_index)); |
| 298 | if (slist[cserver].stratum <= slist[best_server].stratum) { | 299 | if (slist[cserver].stratum <= slist[best_server_index].stratum) { |
| 299 | DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); | 300 | DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server_index)); |
| 300 | /* does it have an equal or better dispersion? */ | 301 | /* does it have an equal or better dispersion? */ |
| 301 | if (slist[cserver].rtdisp <= slist[best_server].rtdisp) { | 302 | if (slist[cserver].rtdisp <= slist[best_server_index].rtdisp) { |
| 302 | DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); | 303 | DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server_index)); |
| 303 | /* does it have a better rtdelay? */ | 304 | /* does it have a better rtdelay? */ |
| 304 | if (slist[cserver].rtdelay < slist[best_server].rtdelay) { | 305 | if (slist[cserver].rtdelay < slist[best_server_index].rtdelay) { |
| 305 | DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); | 306 | DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server_index)); |
| 306 | best_server = cserver; | 307 | best_server_index = cserver; |
| 307 | DBG(printf("peer %d is now our best candidate\n", best_server)); | 308 | DBG(printf("peer %d is now our best candidate\n", best_server_index)); |
| 308 | } | 309 | } |
| 309 | } | 310 | } |
| 310 | } | 311 | } |
| 311 | } | 312 | } |
| 312 | 313 | ||
| 313 | if (best_server >= 0) { | 314 | if (best_server_index >= 0) { |
| 314 | DBG(printf("best server selected: peer %d\n", best_server)); | 315 | DBG(printf("best server selected: peer %d\n", best_server_index)); |
| 315 | return best_server; | 316 | return best_server_index; |
| 316 | } | 317 | } |
| 317 | DBG(printf("no peers meeting synchronization criteria :(\n")); | 318 | DBG(printf("no peers meeting synchronization criteria :(\n")); |
| 318 | return -1; | 319 | return -1; |
| @@ -323,7 +324,11 @@ int best_offset_server(const ntp_server_results *slist, int nservers) { | |||
| 323 | * we don't waste time sitting around waiting for single packets. | 324 | * we don't waste time sitting around waiting for single packets. |
| 324 | * - we also "manually" handle resolving host names and connecting, because | 325 | * - we also "manually" handle resolving host names and connecting, because |
| 325 | * we have to do it in a way that our lazy macros don't handle currently :( */ | 326 | * we have to do it in a way that our lazy macros don't handle currently :( */ |
| 326 | double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) { | 327 | typedef struct { |
| 328 | mp_state_enum offset_result; | ||
| 329 | double offset; | ||
| 330 | } offset_request_wrapper; | ||
| 331 | static offset_request_wrapper offset_request(const char *host, const char *port, int time_offset) { | ||
| 327 | /* setup hints to only return results from getaddrinfo that we'd like */ | 332 | /* setup hints to only return results from getaddrinfo that we'd like */ |
| 328 | struct addrinfo hints; | 333 | struct addrinfo hints; |
| 329 | memset(&hints, 0, sizeof(struct addrinfo)); | 334 | memset(&hints, 0, sizeof(struct addrinfo)); |
| @@ -462,12 +467,18 @@ double offset_request(const char *host, const char *port, mp_state_enum *status, | |||
| 462 | die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); | 467 | die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); |
| 463 | } | 468 | } |
| 464 | 469 | ||
| 470 | offset_request_wrapper result = { | ||
| 471 | .offset = 0, | ||
| 472 | .offset_result = STATE_UNKNOWN, | ||
| 473 | }; | ||
| 474 | |||
| 465 | /* now, pick the best server from the list */ | 475 | /* now, pick the best server from the list */ |
| 466 | double avg_offset = 0.; | 476 | double avg_offset = 0.; |
| 467 | int best_index = best_offset_server(servers, num_hosts); | 477 | int best_index = best_offset_server(servers, num_hosts); |
| 468 | if (best_index < 0) { | 478 | if (best_index < 0) { |
| 469 | *status = STATE_UNKNOWN; | 479 | result.offset_result = STATE_UNKNOWN; |
| 470 | } else { | 480 | } else { |
| 481 | result.offset_result = STATE_OK; | ||
| 471 | /* finally, calculate the average offset */ | 482 | /* finally, calculate the average offset */ |
| 472 | for (int i = 0; i < servers[best_index].num_responses; i++) { | 483 | for (int i = 0; i < servers[best_index].num_responses; i++) { |
| 473 | avg_offset += servers[best_index].offset[i]; | 484 | avg_offset += servers[best_index].offset[i]; |
| @@ -488,22 +499,30 @@ double offset_request(const char *host, const char *port, mp_state_enum *status, | |||
| 488 | if (verbose) { | 499 | if (verbose) { |
| 489 | printf("overall average offset: %.10g\n", avg_offset); | 500 | printf("overall average offset: %.10g\n", avg_offset); |
| 490 | } | 501 | } |
| 491 | return avg_offset; | 502 | |
| 503 | result.offset = avg_offset; | ||
| 504 | return result; | ||
| 492 | } | 505 | } |
| 493 | 506 | ||
| 494 | check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { | 507 | static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { |
| 508 | |||
| 509 | enum { | ||
| 510 | output_format_index = CHAR_MAX + 1, | ||
| 511 | }; | ||
| 512 | |||
| 495 | static struct option longopts[] = {{"version", no_argument, 0, 'V'}, | 513 | static struct option longopts[] = {{"version", no_argument, 0, 'V'}, |
| 496 | {"help", no_argument, 0, 'h'}, | 514 | {"help", no_argument, 0, 'h'}, |
| 497 | {"verbose", no_argument, 0, 'v'}, | 515 | {"verbose", no_argument, 0, 'v'}, |
| 498 | {"use-ipv4", no_argument, 0, '4'}, | 516 | {"use-ipv4", no_argument, 0, '4'}, |
| 499 | {"use-ipv6", no_argument, 0, '6'}, | 517 | {"use-ipv6", no_argument, 0, '6'}, |
| 500 | {"quiet", no_argument, 0, 'q'}, | 518 | {"quiet", no_argument, 0, 'q'}, |
| 501 | {"time-offset", optional_argument, 0, 'o'}, | 519 | {"time-offset", required_argument, 0, 'o'}, |
| 502 | {"warning", required_argument, 0, 'w'}, | 520 | {"warning", required_argument, 0, 'w'}, |
| 503 | {"critical", required_argument, 0, 'c'}, | 521 | {"critical", required_argument, 0, 'c'}, |
| 504 | {"timeout", required_argument, 0, 't'}, | 522 | {"timeout", required_argument, 0, 't'}, |
| 505 | {"hostname", required_argument, 0, 'H'}, | 523 | {"hostname", required_argument, 0, 'H'}, |
| 506 | {"port", required_argument, 0, 'p'}, | 524 | {"port", required_argument, 0, 'p'}, |
| 525 | {"output-format", required_argument, 0, output_format_index}, | ||
| 507 | {0, 0, 0, 0}}; | 526 | {0, 0, 0, 0}}; |
| 508 | 527 | ||
| 509 | if (argc < 2) { | 528 | if (argc < 2) { |
| @@ -515,9 +534,6 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { | |||
| 515 | .config = check_ntp_time_config_init(), | 534 | .config = check_ntp_time_config_init(), |
| 516 | }; | 535 | }; |
| 517 | 536 | ||
| 518 | char *owarn = "60"; | ||
| 519 | char *ocrit = "120"; | ||
| 520 | |||
| 521 | while (true) { | 537 | while (true) { |
| 522 | int option = 0; | 538 | int option = 0; |
| 523 | int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); | 539 | int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); |
| @@ -526,6 +542,17 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { | |||
| 526 | } | 542 | } |
| 527 | 543 | ||
| 528 | switch (option_char) { | 544 | switch (option_char) { |
| 545 | case output_format_index: { | ||
| 546 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 547 | if (!parser.parsing_success) { | ||
| 548 | printf("Invalid output format: %s\n", optarg); | ||
| 549 | exit(STATE_UNKNOWN); | ||
| 550 | } | ||
| 551 | |||
| 552 | result.config.output_format_is_set = true; | ||
| 553 | result.config.output_format = parser.output_format; | ||
| 554 | break; | ||
| 555 | } | ||
| 529 | case 'h': | 556 | case 'h': |
| 530 | print_help(); | 557 | print_help(); |
| 531 | exit(STATE_UNKNOWN); | 558 | exit(STATE_UNKNOWN); |
| @@ -540,12 +567,24 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { | |||
| 540 | case 'q': | 567 | case 'q': |
| 541 | result.config.quiet = true; | 568 | result.config.quiet = true; |
| 542 | break; | 569 | break; |
| 543 | case 'w': | 570 | case 'w': { |
| 544 | owarn = optarg; | 571 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 545 | break; | 572 | if (tmp.error != MP_PARSING_SUCCES) { |
| 546 | case 'c': | 573 | die(STATE_UNKNOWN, "failed to parse warning threshold"); |
| 547 | ocrit = optarg; | 574 | } |
| 548 | break; | 575 | |
| 576 | result.config.offset_thresholds = | ||
| 577 | mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range); | ||
| 578 | } break; | ||
| 579 | case 'c': { | ||
| 580 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 581 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 582 | die(STATE_UNKNOWN, "failed to parse crit threshold"); | ||
| 583 | } | ||
| 584 | |||
| 585 | result.config.offset_thresholds = | ||
| 586 | mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range); | ||
| 587 | } break; | ||
| 549 | case 'H': | 588 | case 'H': |
| 550 | if (!is_host(optarg)) { | 589 | if (!is_host(optarg)) { |
| 551 | usage2(_("Invalid hostname/address"), optarg); | 590 | usage2(_("Invalid hostname/address"), optarg); |
| @@ -582,16 +621,9 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { | |||
| 582 | usage4(_("Hostname was not supplied")); | 621 | usage4(_("Hostname was not supplied")); |
| 583 | } | 622 | } |
| 584 | 623 | ||
| 585 | set_thresholds(&result.config.offset_thresholds, owarn, ocrit); | ||
| 586 | |||
| 587 | return result; | 624 | return result; |
| 588 | } | 625 | } |
| 589 | 626 | ||
| 590 | char *perfd_offset(double offset, thresholds *offset_thresholds) { | ||
| 591 | return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, | ||
| 592 | offset_thresholds->critical->end, false, 0, false, 0); | ||
| 593 | } | ||
| 594 | |||
| 595 | int main(int argc, char *argv[]) { | 627 | int main(int argc, char *argv[]) { |
| 596 | setlocale(LC_ALL, ""); | 628 | setlocale(LC_ALL, ""); |
| 597 | bindtextdomain(PACKAGE, LOCALEDIR); | 629 | bindtextdomain(PACKAGE, LOCALEDIR); |
| @@ -608,52 +640,47 @@ int main(int argc, char *argv[]) { | |||
| 608 | 640 | ||
| 609 | const check_ntp_time_config config = tmp_config.config; | 641 | const check_ntp_time_config config = tmp_config.config; |
| 610 | 642 | ||
| 643 | if (config.output_format_is_set) { | ||
| 644 | mp_set_format(config.output_format); | ||
| 645 | } | ||
| 646 | |||
| 611 | /* initialize alarm signal handling */ | 647 | /* initialize alarm signal handling */ |
| 612 | signal(SIGALRM, socket_timeout_alarm_handler); | 648 | signal(SIGALRM, socket_timeout_alarm_handler); |
| 613 | 649 | ||
| 614 | /* set socket timeout */ | 650 | /* set socket timeout */ |
| 615 | alarm(socket_timeout); | 651 | alarm(socket_timeout); |
| 616 | 652 | ||
| 617 | mp_state_enum offset_result = STATE_OK; | 653 | mp_check overall = mp_check_init(); |
| 618 | mp_state_enum result = STATE_OK; | ||
| 619 | double offset = | ||
| 620 | offset_request(config.server_address, config.port, &offset_result, config.time_offset); | ||
| 621 | if (offset_result == STATE_UNKNOWN) { | ||
| 622 | result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL); | ||
| 623 | } else { | ||
| 624 | result = get_status(fabs(offset), config.offset_thresholds); | ||
| 625 | } | ||
| 626 | 654 | ||
| 627 | char *result_line; | 655 | mp_subcheck sc_offset = mp_subcheck_init(); |
| 628 | switch (result) { | 656 | offset_request_wrapper offset_result = |
| 629 | case STATE_CRITICAL: | 657 | offset_request(config.server_address, config.port, config.time_offset); |
| 630 | xasprintf(&result_line, _("NTP CRITICAL:")); | ||
| 631 | break; | ||
| 632 | case STATE_WARNING: | ||
| 633 | xasprintf(&result_line, _("NTP WARNING:")); | ||
| 634 | break; | ||
| 635 | case STATE_OK: | ||
| 636 | xasprintf(&result_line, _("NTP OK:")); | ||
| 637 | break; | ||
| 638 | default: | ||
| 639 | xasprintf(&result_line, _("NTP UNKNOWN:")); | ||
| 640 | break; | ||
| 641 | } | ||
| 642 | 658 | ||
| 643 | char *perfdata_line; | 659 | if (offset_result.offset_result == STATE_UNKNOWN) { |
| 644 | if (offset_result == STATE_UNKNOWN) { | 660 | sc_offset = |
| 645 | xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); | 661 | mp_set_subcheck_state(sc_offset, (!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL); |
| 646 | xasprintf(&perfdata_line, ""); | 662 | xasprintf(&sc_offset.output, "Offset unknown"); |
| 647 | } else { | 663 | mp_add_subcheck_to_check(&overall, sc_offset); |
| 648 | xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); | 664 | mp_exit(overall); |
| 649 | xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds)); | ||
| 650 | } | 665 | } |
| 651 | printf("%s|%s\n", result_line, perfdata_line); | 666 | |
| 667 | xasprintf(&sc_offset.output, "Offset: %.6fs", offset_result.offset); | ||
| 668 | |||
| 669 | mp_perfdata pd_offset = perfdata_init(); | ||
| 670 | pd_offset = mp_set_pd_value(pd_offset, fabs(offset_result.offset)); | ||
| 671 | pd_offset.label = "offset"; | ||
| 672 | pd_offset.uom = "s"; | ||
| 673 | pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds); | ||
| 674 | |||
| 675 | sc_offset = mp_set_subcheck_state(sc_offset, mp_get_pd_status(pd_offset)); | ||
| 676 | |||
| 677 | mp_add_perfdata_to_subcheck(&sc_offset, pd_offset); | ||
| 678 | mp_add_subcheck_to_check(&overall, sc_offset); | ||
| 652 | 679 | ||
| 653 | if (config.server_address != NULL) { | 680 | if (config.server_address != NULL) { |
| 654 | free(config.server_address); | 681 | free(config.server_address); |
| 655 | } | 682 | } |
| 656 | exit(result); | 683 | mp_exit(overall); |
| 657 | } | 684 | } |
| 658 | 685 | ||
| 659 | void print_help(void) { | 686 | void print_help(void) { |
| @@ -677,10 +704,11 @@ void print_help(void) { | |||
| 677 | printf(" %s\n", _("Offset to result in warning status (seconds)")); | 704 | printf(" %s\n", _("Offset to result in warning status (seconds)")); |
| 678 | printf(" %s\n", "-c, --critical=THRESHOLD"); | 705 | printf(" %s\n", "-c, --critical=THRESHOLD"); |
| 679 | printf(" %s\n", _("Offset to result in critical status (seconds)")); | 706 | printf(" %s\n", _("Offset to result in critical status (seconds)")); |
| 680 | printf(" %s\n", "-o, --time_offset=INTEGER"); | 707 | printf(" %s\n", "-o, --time-offset=INTEGER"); |
| 681 | printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); | 708 | printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); |
| 682 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 709 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
| 683 | printf(UT_VERBOSE); | 710 | printf(UT_VERBOSE); |
| 711 | printf(UT_OUTPUT_FORMAT); | ||
| 684 | 712 | ||
| 685 | printf("\n"); | 713 | printf("\n"); |
| 686 | printf("%s\n", _("This plugin checks the clock offset between the local host and a")); | 714 | printf("%s\n", _("This plugin checks the clock offset between the local host and a")); |
diff --git a/plugins/check_ntp_time.d/config.h b/plugins/check_ntp_time.d/config.h index 99dabbbd..9bbd82aa 100644 --- a/plugins/check_ntp_time.d/config.h +++ b/plugins/check_ntp_time.d/config.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 4 | #include "thresholds.h" | 5 | #include "thresholds.h" |
| 5 | #include <stddef.h> | 6 | #include <stddef.h> |
| 6 | 7 | ||
| @@ -11,7 +12,10 @@ typedef struct { | |||
| 11 | bool quiet; | 12 | bool quiet; |
| 12 | int time_offset; | 13 | int time_offset; |
| 13 | 14 | ||
| 14 | thresholds *offset_thresholds; | 15 | mp_thresholds offset_thresholds; |
| 16 | |||
| 17 | bool output_format_is_set; | ||
| 18 | mp_output_format output_format; | ||
| 15 | } check_ntp_time_config; | 19 | } check_ntp_time_config; |
| 16 | 20 | ||
| 17 | check_ntp_time_config check_ntp_time_config_init() { | 21 | check_ntp_time_config check_ntp_time_config_init() { |
| @@ -22,7 +26,18 @@ check_ntp_time_config check_ntp_time_config_init() { | |||
| 22 | .quiet = false, | 26 | .quiet = false, |
| 23 | .time_offset = 0, | 27 | .time_offset = 0, |
| 24 | 28 | ||
| 25 | .offset_thresholds = NULL, | 29 | .offset_thresholds = mp_thresholds_init(), |
| 30 | |||
| 31 | .output_format_is_set = false, | ||
| 26 | }; | 32 | }; |
| 33 | |||
| 34 | mp_range warning = mp_range_init(); | ||
| 35 | warning = mp_range_set_end(warning, mp_create_pd_value(60)); | ||
| 36 | tmp.offset_thresholds = mp_thresholds_set_warn(tmp.offset_thresholds, warning); | ||
| 37 | |||
| 38 | mp_range critical = mp_range_init(); | ||
| 39 | critical = mp_range_set_end(warning, mp_create_pd_value(120)); | ||
| 40 | tmp.offset_thresholds = mp_thresholds_set_crit(tmp.offset_thresholds, critical); | ||
| 41 | |||
| 27 | return tmp; | 42 | return tmp; |
| 28 | } | 43 | } |
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c index 793a686f..0ce75e0a 100644 --- a/plugins/check_pgsql.c +++ b/plugins/check_pgsql.c | |||
| @@ -28,27 +28,29 @@ | |||
| 28 | * | 28 | * |
| 29 | *****************************************************************************/ | 29 | *****************************************************************************/ |
| 30 | 30 | ||
| 31 | #include "output.h" | ||
| 32 | #include "perfdata.h" | ||
| 31 | #include "states.h" | 33 | #include "states.h" |
| 32 | const char *progname = "check_pgsql"; | ||
| 33 | const char *copyright = "1999-2024"; | ||
| 34 | const char *email = "devel@monitoring-plugins.org"; | ||
| 35 | |||
| 36 | #include "common.h" | 34 | #include "common.h" |
| 37 | #include "utils.h" | 35 | #include "utils.h" |
| 38 | #include "utils_cmd.h" | 36 | #include "utils_cmd.h" |
| 39 | #include "check_pgsql.d/config.h" | 37 | #include "check_pgsql.d/config.h" |
| 40 | #include "thresholds.h" | 38 | #include "thresholds.h" |
| 41 | |||
| 42 | #include "netutils.h" | 39 | #include "netutils.h" |
| 43 | #include <libpq-fe.h> | 40 | #include <libpq-fe.h> |
| 44 | #include <pg_config_manual.h> | 41 | #include <pg_config_manual.h> |
| 45 | 42 | ||
| 43 | const char *progname = "check_pgsql"; | ||
| 44 | const char *copyright = "1999-2024"; | ||
| 45 | const char *email = "devel@monitoring-plugins.org"; | ||
| 46 | |||
| 46 | #define DEFAULT_HOST "127.0.0.1" | 47 | #define DEFAULT_HOST "127.0.0.1" |
| 47 | 48 | ||
| 48 | /* return the PSQL server version as a 3-tuple */ | 49 | /* return the PSQL server version as a 3-tuple */ |
| 49 | #define PSQL_SERVER_VERSION3(server_version) \ | 50 | #define PSQL_SERVER_VERSION3(server_version) \ |
| 50 | (server_version) / 10000, (server_version) / 100 - (int)((server_version) / 10000) * 100, \ | 51 | ((server_version) / 10000), \ |
| 51 | (server_version) - (int)((server_version) / 100) * 100 | 52 | (((server_version) / 100) - (int)(((server_version) / 10000) * 100)), \ |
| 53 | (server_version) - (int)(((server_version) / 100) * 100) | ||
| 52 | /* return true if the given host is a UNIX domain socket */ | 54 | /* return true if the given host is a UNIX domain socket */ |
| 53 | #define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host))) | 55 | #define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host))) |
| 54 | /* return a 3-tuple identifying a host/port independent of the socket type */ | 56 | /* return a 3-tuple identifying a host/port independent of the socket type */ |
| @@ -64,15 +66,25 @@ static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv | |||
| 64 | 66 | ||
| 65 | static void print_help(void); | 67 | static void print_help(void); |
| 66 | static bool is_pg_logname(char * /*username*/); | 68 | static bool is_pg_logname(char * /*username*/); |
| 67 | static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[], | 69 | |
| 68 | thresholds * /*qthresholds*/, char * /*query_warning*/, | 70 | typedef enum { |
| 69 | char * /*query_critical*/); | 71 | QUERY_OK, |
| 72 | ERROR_WITH_QUERY, // critical | ||
| 73 | NO_ROWS_RETURNED, // warning | ||
| 74 | NO_COLUMNS_RETURNED, // warning | ||
| 75 | NO_DATA_RETURNED, // critica/ | ||
| 76 | RESULT_IS_NOT_NUMERIC // critical | ||
| 77 | } do_query_errorcode; | ||
| 78 | |||
| 79 | typedef struct { | ||
| 80 | do_query_errorcode error_code; | ||
| 81 | double numerical_result; | ||
| 82 | } do_query_wrapper; | ||
| 83 | static do_query_wrapper do_query(PGconn * /*conn*/, char * /*query*/); | ||
| 70 | void print_usage(void); | 84 | void print_usage(void); |
| 71 | 85 | ||
| 72 | static int verbose = 0; | 86 | static int verbose = 0; |
| 73 | 87 | ||
| 74 | #define OPTID_QUERYNAME -1000 | ||
| 75 | |||
| 76 | /****************************************************************************** | 88 | /****************************************************************************** |
| 77 | 89 | ||
| 78 | The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@ | 90 | The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@ |
| @@ -138,8 +150,8 @@ int main(int argc, char **argv) { | |||
| 138 | 150 | ||
| 139 | const check_pgsql_config config = tmp_config.config; | 151 | const check_pgsql_config config = tmp_config.config; |
| 140 | 152 | ||
| 141 | if (verbose > 2) { | 153 | if (config.output_format_is_set) { |
| 142 | printf("Arguments initialized\n"); | 154 | mp_set_format(config.output_format); |
| 143 | } | 155 | } |
| 144 | 156 | ||
| 145 | /* Set signal handling and alarm */ | 157 | /* Set signal handling and alarm */ |
| @@ -199,21 +211,41 @@ int main(int argc, char **argv) { | |||
| 199 | if (verbose) { | 211 | if (verbose) { |
| 200 | printf("Verifying connection\n"); | 212 | printf("Verifying connection\n"); |
| 201 | } | 213 | } |
| 214 | |||
| 215 | mp_check overall = mp_check_init(); | ||
| 216 | |||
| 217 | mp_subcheck sc_connection = mp_subcheck_init(); | ||
| 218 | |||
| 202 | if (PQstatus(conn) == CONNECTION_BAD) { | 219 | if (PQstatus(conn) == CONNECTION_BAD) { |
| 203 | printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn)); | 220 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_CRITICAL); |
| 221 | xasprintf(&sc_connection.output, "no connection to '%s' (%s)", config.dbName, | ||
| 222 | PQerrorMessage(conn)); | ||
| 204 | PQfinish(conn); | 223 | PQfinish(conn); |
| 205 | return STATE_CRITICAL; | 224 | mp_add_subcheck_to_check(&overall, sc_connection); |
| 206 | } | 225 | mp_exit(overall); |
| 207 | |||
| 208 | mp_state_enum status = STATE_UNKNOWN; | ||
| 209 | if (elapsed_time > config.tcrit) { | ||
| 210 | status = STATE_CRITICAL; | ||
| 211 | } else if (elapsed_time > config.twarn) { | ||
| 212 | status = STATE_WARNING; | ||
| 213 | } else { | 226 | } else { |
| 214 | status = STATE_OK; | 227 | sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK); |
| 228 | xasprintf(&sc_connection.output, "connected to '%s'", config.dbName); | ||
| 229 | mp_add_subcheck_to_check(&overall, sc_connection); | ||
| 215 | } | 230 | } |
| 216 | 231 | ||
| 232 | mp_subcheck sc_connection_time = mp_subcheck_init(); | ||
| 233 | sc_connection_time = mp_set_subcheck_default_state(sc_connection_time, STATE_UNKNOWN); | ||
| 234 | |||
| 235 | xasprintf(&sc_connection_time.output, "connection time: %.10g", elapsed_time); | ||
| 236 | |||
| 237 | mp_perfdata pd_connection_time = perfdata_init(); | ||
| 238 | pd_connection_time.label = "time"; | ||
| 239 | pd_connection_time.uom = "s"; | ||
| 240 | pd_connection_time = mp_set_pd_value(pd_connection_time, elapsed_time); | ||
| 241 | pd_connection_time = mp_pd_set_thresholds(pd_connection_time, config.time_thresholds); | ||
| 242 | |||
| 243 | mp_add_perfdata_to_subcheck(&sc_connection_time, pd_connection_time); | ||
| 244 | sc_connection_time = | ||
| 245 | mp_set_subcheck_state(sc_connection_time, mp_get_pd_status(pd_connection_time)); | ||
| 246 | |||
| 247 | mp_add_subcheck_to_check(&overall, sc_connection_time); | ||
| 248 | |||
| 217 | if (verbose) { | 249 | if (verbose) { |
| 218 | char *server_host = PQhost(conn); | 250 | char *server_host = PQhost(conn); |
| 219 | int server_version = PQserverVersion(conn); | 251 | int server_version = PQserverVersion(conn); |
| @@ -225,25 +257,87 @@ int main(int argc, char **argv) { | |||
| 225 | PSQL_SERVER_VERSION3(server_version), PQprotocolVersion(conn), PQbackendPID(conn)); | 257 | PSQL_SERVER_VERSION3(server_version), PQprotocolVersion(conn), PQbackendPID(conn)); |
| 226 | } | 258 | } |
| 227 | 259 | ||
| 228 | printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time, | ||
| 229 | fperfdata("time", elapsed_time, "s", (config.twarn > 0.0), config.twarn, | ||
| 230 | (config.tcrit > 0.0), config.tcrit, true, 0, false, 0)); | ||
| 231 | |||
| 232 | mp_state_enum query_status = STATE_UNKNOWN; | ||
| 233 | if (config.pgquery) { | 260 | if (config.pgquery) { |
| 234 | query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds, | 261 | mp_subcheck sc_query = mp_subcheck_init(); |
| 235 | config.query_warning, config.query_critical); | 262 | sc_query = mp_set_subcheck_default_state(sc_query, STATE_UNKNOWN); |
| 263 | if (config.pgqueryname) { | ||
| 264 | xasprintf(&sc_query.output, "query '%s'", config.pgqueryname); | ||
| 265 | } else { | ||
| 266 | xasprintf(&sc_query.output, "query '%s'", config.pgquery); | ||
| 267 | } | ||
| 268 | |||
| 269 | do_query_wrapper query_result = do_query(conn, config.pgquery); | ||
| 270 | |||
| 271 | switch (query_result.error_code) { | ||
| 272 | case QUERY_OK: { | ||
| 273 | // Query was successful and there is a numerical result | ||
| 274 | sc_query = mp_set_subcheck_state(sc_query, STATE_OK); | ||
| 275 | xasprintf(&sc_query.output, "%s succeeded", sc_query.output); | ||
| 276 | |||
| 277 | mp_perfdata pd_query = perfdata_init(); | ||
| 278 | pd_query = mp_set_pd_value(pd_query, query_result.numerical_result); | ||
| 279 | pd_query = mp_pd_set_thresholds(pd_query, config.qthresholds); | ||
| 280 | pd_query.label = "query"; | ||
| 281 | |||
| 282 | mp_subcheck sc_query_compare = mp_subcheck_init(); | ||
| 283 | mp_state_enum query_compare_state = mp_get_pd_status(pd_query); | ||
| 284 | |||
| 285 | sc_query_compare = mp_set_subcheck_state(sc_query_compare, query_compare_state); | ||
| 286 | mp_add_perfdata_to_subcheck(&sc_query_compare, pd_query); | ||
| 287 | |||
| 288 | if (query_compare_state == STATE_OK) { | ||
| 289 | xasprintf(&sc_query_compare.output, "query result '%f' is within thresholds", | ||
| 290 | query_result.numerical_result); | ||
| 291 | } else { | ||
| 292 | xasprintf(&sc_query_compare.output, "query result '%f' is violating thresholds", | ||
| 293 | query_result.numerical_result); | ||
| 294 | } | ||
| 295 | mp_add_subcheck_to_check(&overall, sc_query_compare); | ||
| 296 | |||
| 297 | } break; | ||
| 298 | case ERROR_WITH_QUERY: | ||
| 299 | xasprintf(&sc_query.output, "%s - Error with query: %s", sc_query.output, | ||
| 300 | PQerrorMessage(conn)); | ||
| 301 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 302 | break; | ||
| 303 | case NO_ROWS_RETURNED: | ||
| 304 | xasprintf(&sc_query.output, "%s - no rows were returned by the query", sc_query.output); | ||
| 305 | sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING); | ||
| 306 | break; | ||
| 307 | case NO_COLUMNS_RETURNED: | ||
| 308 | xasprintf(&sc_query.output, "%s - no columns were returned by the query", | ||
| 309 | sc_query.output); | ||
| 310 | sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING); | ||
| 311 | break; | ||
| 312 | case NO_DATA_RETURNED: | ||
| 313 | xasprintf(&sc_query.output, "%s - no data was returned by the query", sc_query.output); | ||
| 314 | sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING); | ||
| 315 | break; | ||
| 316 | case RESULT_IS_NOT_NUMERIC: | ||
| 317 | xasprintf(&sc_query.output, "%s - result of the query is not numeric", sc_query.output); | ||
| 318 | sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); | ||
| 319 | break; | ||
| 320 | }; | ||
| 321 | |||
| 322 | mp_add_subcheck_to_check(&overall, sc_query); | ||
| 236 | } | 323 | } |
| 237 | 324 | ||
| 238 | if (verbose) { | 325 | if (verbose) { |
| 239 | printf("Closing connection\n"); | 326 | printf("Closing connection\n"); |
| 240 | } | 327 | } |
| 241 | PQfinish(conn); | 328 | PQfinish(conn); |
| 242 | return (config.pgquery && query_status > status) ? query_status : status; | 329 | |
| 330 | mp_exit(overall); | ||
| 243 | } | 331 | } |
| 244 | 332 | ||
| 245 | /* process command-line arguments */ | 333 | /* process command-line arguments */ |
| 246 | check_pgsql_config_wrapper process_arguments(int argc, char **argv) { | 334 | static check_pgsql_config_wrapper process_arguments(int argc, char **argv) { |
| 335 | |||
| 336 | enum { | ||
| 337 | OPTID_QUERYNAME = CHAR_MAX + 1, | ||
| 338 | output_format_index, | ||
| 339 | }; | ||
| 340 | |||
| 247 | static struct option longopts[] = {{"help", no_argument, 0, 'h'}, | 341 | static struct option longopts[] = {{"help", no_argument, 0, 'h'}, |
| 248 | {"version", no_argument, 0, 'V'}, | 342 | {"version", no_argument, 0, 'V'}, |
| 249 | {"timeout", required_argument, 0, 't'}, | 343 | {"timeout", required_argument, 0, 't'}, |
| @@ -261,6 +355,7 @@ check_pgsql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 261 | {"query_critical", required_argument, 0, 'C'}, | 355 | {"query_critical", required_argument, 0, 'C'}, |
| 262 | {"query_warning", required_argument, 0, 'W'}, | 356 | {"query_warning", required_argument, 0, 'W'}, |
| 263 | {"verbose", no_argument, 0, 'v'}, | 357 | {"verbose", no_argument, 0, 'v'}, |
| 358 | {"output-format", required_argument, 0, output_format_index}, | ||
| 264 | {0, 0, 0, 0}}; | 359 | {0, 0, 0, 0}}; |
| 265 | 360 | ||
| 266 | check_pgsql_config_wrapper result = { | 361 | check_pgsql_config_wrapper result = { |
| @@ -278,6 +373,17 @@ check_pgsql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 278 | } | 373 | } |
| 279 | 374 | ||
| 280 | switch (option_char) { | 375 | switch (option_char) { |
| 376 | case output_format_index: { | ||
| 377 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 378 | if (!parser.parsing_success) { | ||
| 379 | printf("Invalid output format: %s\n", optarg); | ||
| 380 | exit(STATE_UNKNOWN); | ||
| 381 | } | ||
| 382 | |||
| 383 | result.config.output_format_is_set = true; | ||
| 384 | result.config.output_format = parser.output_format; | ||
| 385 | break; | ||
| 386 | } | ||
| 281 | case '?': /* usage */ | 387 | case '?': /* usage */ |
| 282 | usage5(); | 388 | usage5(); |
| 283 | case 'h': /* help */ | 389 | case 'h': /* help */ |
| @@ -293,26 +399,40 @@ check_pgsql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 293 | timeout_interval = atoi(optarg); | 399 | timeout_interval = atoi(optarg); |
| 294 | } | 400 | } |
| 295 | break; | 401 | break; |
| 296 | case 'c': /* critical time threshold */ | 402 | case 'c': /* critical time threshold */ { |
| 297 | if (!is_nonnegative(optarg)) { | 403 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 298 | usage2(_("Critical threshold must be a positive integer"), optarg); | 404 | if (tmp.error != MP_PARSING_SUCCES) { |
| 299 | } else { | 405 | die(STATE_UNKNOWN, "failed to parse critical time threshold"); |
| 300 | result.config.tcrit = strtod(optarg, NULL); | ||
| 301 | } | 406 | } |
| 302 | break; | 407 | result.config.time_thresholds = |
| 303 | case 'w': /* warning time threshold */ | 408 | mp_thresholds_set_crit(result.config.time_thresholds, tmp.range); |
| 304 | if (!is_nonnegative(optarg)) { | 409 | } break; |
| 305 | usage2(_("Warning threshold must be a positive integer"), optarg); | 410 | case 'w': /* warning time threshold */ { |
| 306 | } else { | 411 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 307 | result.config.twarn = strtod(optarg, NULL); | 412 | if (tmp.error != MP_PARSING_SUCCES) { |
| 413 | die(STATE_UNKNOWN, "failed to parse warning time threshold"); | ||
| 308 | } | 414 | } |
| 309 | break; | 415 | result.config.time_thresholds = |
| 310 | case 'C': /* critical query threshold */ | 416 | mp_thresholds_set_warn(result.config.time_thresholds, tmp.range); |
| 311 | result.config.query_critical = optarg; | 417 | } break; |
| 312 | break; | 418 | case 'C': /* critical query threshold */ { |
| 313 | case 'W': /* warning query threshold */ | 419 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 314 | result.config.query_warning = optarg; | 420 | if (tmp.error != MP_PARSING_SUCCES) { |
| 315 | break; | 421 | die(STATE_UNKNOWN, "failed to parse critical query threshold"); |
| 422 | } | ||
| 423 | |||
| 424 | result.config.qthresholds = | ||
| 425 | mp_thresholds_set_crit(result.config.qthresholds, tmp.range); | ||
| 426 | |||
| 427 | } break; | ||
| 428 | case 'W': /* warning query threshold */ { | ||
| 429 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 430 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 431 | die(STATE_UNKNOWN, "failed to parse warning query threshold"); | ||
| 432 | } | ||
| 433 | result.config.qthresholds = | ||
| 434 | mp_thresholds_set_warn(result.config.qthresholds, tmp.range); | ||
| 435 | } break; | ||
| 316 | case 'H': /* host */ | 436 | case 'H': /* host */ |
| 317 | if ((*optarg != '/') && (!is_host(optarg))) { | 437 | if ((*optarg != '/') && (!is_host(optarg))) { |
| 318 | usage2(_("Invalid hostname/address"), optarg); | 438 | usage2(_("Invalid hostname/address"), optarg); |
| @@ -363,9 +483,6 @@ check_pgsql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 363 | } | 483 | } |
| 364 | } | 484 | } |
| 365 | 485 | ||
| 366 | set_thresholds(&result.config.qthresholds, result.config.query_warning, | ||
| 367 | result.config.query_critical); | ||
| 368 | |||
| 369 | return result; | 486 | return result; |
| 370 | } | 487 | } |
| 371 | 488 | ||
| @@ -393,7 +510,7 @@ should be added.</para> | |||
| 393 | -@@ | 510 | -@@ |
| 394 | ******************************************************************************/ | 511 | ******************************************************************************/ |
| 395 | 512 | ||
| 396 | bool is_pg_logname(char *username) { | 513 | static bool is_pg_logname(char *username) { |
| 397 | if (strlen(username) > NAMEDATALEN - 1) { | 514 | if (strlen(username) > NAMEDATALEN - 1) { |
| 398 | return (false); | 515 | return (false); |
| 399 | } | 516 | } |
| @@ -447,12 +564,13 @@ void print_help(void) { | |||
| 447 | printf(" %s\n", "--queryname=STRING"); | 564 | printf(" %s\n", "--queryname=STRING"); |
| 448 | printf(" %s\n", _("A name for the query, this string is used instead of the query")); | 565 | printf(" %s\n", _("A name for the query, this string is used instead of the query")); |
| 449 | printf(" %s\n", _("in the long output of the plugin")); | 566 | printf(" %s\n", _("in the long output of the plugin")); |
| 450 | printf(" %s\n", "-W, --query-warning=RANGE"); | 567 | printf(" %s\n", "-W, --query_warning=RANGE"); |
| 451 | printf(" %s\n", _("SQL query value to result in warning status (double)")); | 568 | printf(" %s\n", _("SQL query value to result in warning status (double)")); |
| 452 | printf(" %s\n", "-C, --query-critical=RANGE"); | 569 | printf(" %s\n", "-C, --query_critical=RANGE"); |
| 453 | printf(" %s\n", _("SQL query value to result in critical status (double)")); | 570 | printf(" %s\n", _("SQL query value to result in critical status (double)")); |
| 454 | 571 | ||
| 455 | printf(UT_VERBOSE); | 572 | printf(UT_VERBOSE); |
| 573 | printf(UT_OUTPUT_FORMAT); | ||
| 456 | 574 | ||
| 457 | printf("\n"); | 575 | printf("\n"); |
| 458 | printf(" %s\n", _("All parameters are optional.")); | 576 | printf(" %s\n", _("All parameters are optional.")); |
| @@ -509,33 +627,44 @@ void print_usage(void) { | |||
| 509 | "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n"); | 627 | "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n"); |
| 510 | } | 628 | } |
| 511 | 629 | ||
| 512 | mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds, | 630 | static do_query_wrapper do_query(PGconn *conn, char *query) { |
| 513 | char *query_warning, char *query_critical) { | ||
| 514 | if (verbose) { | 631 | if (verbose) { |
| 515 | printf("Executing SQL query \"%s\".\n", query); | 632 | printf("Executing SQL query \"%s\".\n", query); |
| 516 | } | 633 | } |
| 517 | PGresult *res = PQexec(conn, query); | 634 | PGresult *res = PQexec(conn, query); |
| 518 | 635 | ||
| 636 | do_query_wrapper result = { | ||
| 637 | .error_code = QUERY_OK, | ||
| 638 | }; | ||
| 639 | |||
| 519 | if (PGRES_TUPLES_OK != PQresultStatus(res)) { | 640 | if (PGRES_TUPLES_OK != PQresultStatus(res)) { |
| 520 | printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), | 641 | // TODO |
| 521 | PQerrorMessage(conn)); | 642 | // printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), |
| 522 | return STATE_CRITICAL; | 643 | // PQerrorMessage(conn)); |
| 644 | result.error_code = ERROR_WITH_QUERY; | ||
| 645 | return result; | ||
| 523 | } | 646 | } |
| 524 | 647 | ||
| 525 | if (PQntuples(res) < 1) { | 648 | if (PQntuples(res) < 1) { |
| 526 | printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); | 649 | // TODO |
| 527 | return STATE_WARNING; | 650 | // printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); |
| 651 | result.error_code = NO_ROWS_RETURNED; | ||
| 652 | return result; | ||
| 528 | } | 653 | } |
| 529 | 654 | ||
| 530 | if (PQnfields(res) < 1) { | 655 | if (PQnfields(res) < 1) { |
| 531 | printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); | 656 | // TODO |
| 532 | return STATE_WARNING; | 657 | // printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); |
| 658 | result.error_code = NO_COLUMNS_RETURNED; | ||
| 659 | return result; | ||
| 533 | } | 660 | } |
| 534 | 661 | ||
| 535 | char *val_str = PQgetvalue(res, 0, 0); | 662 | char *val_str = PQgetvalue(res, 0, 0); |
| 536 | if (!val_str) { | 663 | if (!val_str) { |
| 537 | printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); | 664 | // TODO |
| 538 | return STATE_CRITICAL; | 665 | // printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); |
| 666 | result.error_code = NO_DATA_RETURNED; | ||
| 667 | return result; | ||
| 539 | } | 668 | } |
| 540 | 669 | ||
| 541 | char *endptr = NULL; | 670 | char *endptr = NULL; |
| @@ -545,8 +674,10 @@ mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thre | |||
| 545 | } | 674 | } |
| 546 | 675 | ||
| 547 | if (endptr == val_str) { | 676 | if (endptr == val_str) { |
| 548 | printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); | 677 | // TODO |
| 549 | return STATE_CRITICAL; | 678 | // printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); |
| 679 | result.error_code = RESULT_IS_NOT_NUMERIC; | ||
| 680 | return result; | ||
| 550 | } | 681 | } |
| 551 | 682 | ||
| 552 | if ((endptr != NULL) && (*endptr != '\0')) { | 683 | if ((endptr != NULL) && (*endptr != '\0')) { |
| @@ -555,24 +686,7 @@ mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thre | |||
| 555 | } | 686 | } |
| 556 | } | 687 | } |
| 557 | 688 | ||
| 558 | mp_state_enum my_status = get_status(value, qthresholds); | 689 | result.numerical_result = value; |
| 559 | printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK") | ||
| 560 | : (my_status == STATE_WARNING) ? _("WARNING") | ||
| 561 | : (my_status == STATE_CRITICAL) ? _("CRITICAL") | ||
| 562 | : _("UNKNOWN")); | ||
| 563 | if (pgqueryname) { | ||
| 564 | printf(_("%s returned %f"), pgqueryname, value); | ||
| 565 | } else { | ||
| 566 | printf(_("'%s' returned %f"), query, value); | ||
| 567 | } | ||
| 568 | 690 | ||
| 569 | printf("|query=%f;%s;%s;;\n", value, query_warning ? query_warning : "", | 691 | return result; |
| 570 | query_critical ? query_critical : ""); | ||
| 571 | if (PQnfields(res) > 1) { | ||
| 572 | char *extra_info = PQgetvalue(res, 0, 1); | ||
| 573 | if (extra_info != NULL) { | ||
| 574 | printf("Extra Info: %s\n", extra_info); | ||
| 575 | } | ||
| 576 | } | ||
| 577 | return my_status; | ||
| 578 | } | 692 | } |
diff --git a/plugins/check_pgsql.d/config.h b/plugins/check_pgsql.d/config.h index 2d4b8b89..7cf0637b 100644 --- a/plugins/check_pgsql.d/config.h +++ b/plugins/check_pgsql.d/config.h | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 5 | #include "perfdata.h" | ||
| 4 | #include "thresholds.h" | 6 | #include "thresholds.h" |
| 5 | #include <stddef.h> | 7 | #include <stddef.h> |
| 6 | #include <pg_config_manual.h> | 8 | #include <pg_config_manual.h> |
| @@ -24,11 +26,11 @@ typedef struct { | |||
| 24 | char *pgquery; | 26 | char *pgquery; |
| 25 | char *pgqueryname; | 27 | char *pgqueryname; |
| 26 | 28 | ||
| 27 | double twarn; | 29 | mp_thresholds time_thresholds; |
| 28 | double tcrit; | 30 | mp_thresholds qthresholds; |
| 29 | thresholds *qthresholds; | 31 | |
| 30 | char *query_warning; | 32 | bool output_format_is_set; |
| 31 | char *query_critical; | 33 | mp_output_format output_format; |
| 32 | } check_pgsql_config; | 34 | } check_pgsql_config; |
| 33 | 35 | ||
| 34 | /* begin, by setting the parameters for a backend connection if the | 36 | /* begin, by setting the parameters for a backend connection if the |
| @@ -51,11 +53,18 @@ check_pgsql_config check_pgsql_config_init() { | |||
| 51 | .pgquery = NULL, | 53 | .pgquery = NULL, |
| 52 | .pgqueryname = NULL, | 54 | .pgqueryname = NULL, |
| 53 | 55 | ||
| 54 | .twarn = (double)DEFAULT_WARN, | 56 | .time_thresholds = mp_thresholds_init(), |
| 55 | .tcrit = (double)DEFAULT_CRIT, | 57 | .qthresholds = mp_thresholds_init(), |
| 56 | .qthresholds = NULL, | 58 | |
| 57 | .query_warning = NULL, | 59 | .output_format_is_set = false, |
| 58 | .query_critical = NULL, | ||
| 59 | }; | 60 | }; |
| 61 | |||
| 62 | mp_range tmp_range = mp_range_init(); | ||
| 63 | tmp_range = mp_range_set_end(tmp_range, mp_create_pd_value(DEFAULT_WARN)); | ||
| 64 | tmp.time_thresholds = mp_thresholds_set_warn(tmp.time_thresholds, tmp_range); | ||
| 65 | |||
| 66 | tmp_range = mp_range_set_end(tmp_range, mp_create_pd_value(DEFAULT_CRIT)); | ||
| 67 | tmp.time_thresholds = mp_thresholds_set_crit(tmp.time_thresholds, tmp_range); | ||
| 68 | |||
| 60 | return tmp; | 69 | return tmp; |
| 61 | } | 70 | } |
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c index 83ad575c..e806ad29 100644 --- a/plugins/check_smtp.c +++ b/plugins/check_smtp.c | |||
| @@ -28,20 +28,25 @@ | |||
| 28 | * | 28 | * |
| 29 | *****************************************************************************/ | 29 | *****************************************************************************/ |
| 30 | 30 | ||
| 31 | const char *progname = "check_smtp"; | ||
| 32 | const char *copyright = "2000-2024"; | ||
| 33 | const char *email = "devel@monitoring-plugins.org"; | ||
| 34 | |||
| 35 | #include "common.h" | 31 | #include "common.h" |
| 36 | #include "netutils.h" | 32 | #include "netutils.h" |
| 33 | #include "output.h" | ||
| 34 | #include "perfdata.h" | ||
| 35 | #include "thresholds.h" | ||
| 37 | #include "utils.h" | 36 | #include "utils.h" |
| 38 | #include "base64.h" | 37 | #include "base64.h" |
| 39 | #include "regex.h" | 38 | #include "regex.h" |
| 40 | 39 | ||
| 40 | #include <bits/getopt_ext.h> | ||
| 41 | #include <ctype.h> | 41 | #include <ctype.h> |
| 42 | #include <string.h> | ||
| 42 | #include "check_smtp.d/config.h" | 43 | #include "check_smtp.d/config.h" |
| 43 | #include "../lib/states.h" | 44 | #include "../lib/states.h" |
| 44 | 45 | ||
| 46 | const char *progname = "check_smtp"; | ||
| 47 | const char *copyright = "2000-2024"; | ||
| 48 | const char *email = "devel@monitoring-plugins.org"; | ||
| 49 | |||
| 45 | #define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n" | 50 | #define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n" |
| 46 | #define SMTP_HELO "HELO " | 51 | #define SMTP_HELO "HELO " |
| 47 | #define SMTP_EHLO "EHLO " | 52 | #define SMTP_EHLO "EHLO " |
| @@ -111,6 +116,10 @@ int main(int argc, char **argv) { | |||
| 111 | 116 | ||
| 112 | const check_smtp_config config = tmp_config.config; | 117 | const check_smtp_config config = tmp_config.config; |
| 113 | 118 | ||
| 119 | if (config.output_format_is_set) { | ||
| 120 | mp_set_format(config.output_format); | ||
| 121 | } | ||
| 122 | |||
| 114 | /* If localhostname not set on command line, use gethostname to set */ | 123 | /* If localhostname not set on command line, use gethostname to set */ |
| 115 | char *localhostname = config.localhostname; | 124 | char *localhostname = config.localhostname; |
| 116 | if (!localhostname) { | 125 | if (!localhostname) { |
| @@ -161,359 +170,459 @@ int main(int argc, char **argv) { | |||
| 161 | gettimeofday(&start_time, NULL); | 170 | gettimeofday(&start_time, NULL); |
| 162 | 171 | ||
| 163 | int socket_descriptor = 0; | 172 | int socket_descriptor = 0; |
| 173 | |||
| 164 | /* try to connect to the host at the given port number */ | 174 | /* try to connect to the host at the given port number */ |
| 165 | mp_state_enum result = | 175 | mp_state_enum tcp_result = |
| 166 | my_tcp_connect(config.server_address, config.server_port, &socket_descriptor); | 176 | my_tcp_connect(config.server_address, config.server_port, &socket_descriptor); |
| 167 | 177 | ||
| 168 | char *error_msg = ""; | 178 | mp_check overall = mp_check_init(); |
| 179 | mp_subcheck sc_tcp_connect = mp_subcheck_init(); | ||
| 169 | char buffer[MAX_INPUT_BUFFER]; | 180 | char buffer[MAX_INPUT_BUFFER]; |
| 170 | bool ssl_established = false; | 181 | bool ssl_established = false; |
| 171 | if (result == STATE_OK) { /* we connected */ | 182 | |
| 172 | /* If requested, send PROXY header */ | 183 | if (tcp_result != STATE_OK) { |
| 173 | if (config.use_proxy_prefix) { | 184 | // Connect failed |
| 174 | if (verbose) { | 185 | sc_tcp_connect = mp_set_subcheck_state(sc_tcp_connect, STATE_CRITICAL); |
| 175 | printf("Sending header %s\n", PROXY_PREFIX); | 186 | xasprintf(&sc_tcp_connect.output, "TCP connect to '%s' failed", config.server_address); |
| 176 | } | 187 | mp_add_subcheck_to_check(&overall, sc_tcp_connect); |
| 177 | my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established); | 188 | mp_exit(overall); |
| 189 | } | ||
| 190 | |||
| 191 | /* we connected */ | ||
| 192 | /* If requested, send PROXY header */ | ||
| 193 | if (config.use_proxy_prefix) { | ||
| 194 | if (verbose) { | ||
| 195 | printf("Sending header %s\n", PROXY_PREFIX); | ||
| 178 | } | 196 | } |
| 197 | my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established); | ||
| 198 | } | ||
| 179 | 199 | ||
| 180 | #ifdef HAVE_SSL | 200 | #ifdef HAVE_SSL |
| 181 | if (config.use_ssl) { | 201 | if (config.use_ssl) { |
| 182 | result = np_net_ssl_init_with_hostname(socket_descriptor, | 202 | int tls_result = np_net_ssl_init_with_hostname( |
| 183 | (config.use_sni ? config.server_address : NULL)); | 203 | socket_descriptor, (config.use_sni ? config.server_address : NULL)); |
| 184 | if (result != STATE_OK) { | 204 | |
| 185 | printf(_("CRITICAL - Cannot create SSL context.\n")); | 205 | mp_subcheck sc_tls_connection = mp_subcheck_init(); |
| 186 | close(socket_descriptor); | 206 | |
| 187 | np_net_ssl_cleanup(); | 207 | if (tls_result != STATE_OK) { |
| 188 | exit(STATE_CRITICAL); | 208 | close(socket_descriptor); |
| 189 | } | 209 | np_net_ssl_cleanup(); |
| 190 | ssl_established = true; | 210 | |
| 211 | sc_tls_connection = mp_set_subcheck_state(sc_tls_connection, STATE_CRITICAL); | ||
| 212 | xasprintf(&sc_tls_connection.output, "cannot create TLS context"); | ||
| 213 | mp_add_subcheck_to_check(&overall, sc_tls_connection); | ||
| 214 | mp_exit(overall); | ||
| 191 | } | 215 | } |
| 216 | |||
| 217 | sc_tls_connection = mp_set_subcheck_state(sc_tls_connection, STATE_OK); | ||
| 218 | xasprintf(&sc_tls_connection.output, "TLS context established"); | ||
| 219 | mp_add_subcheck_to_check(&overall, sc_tls_connection); | ||
| 220 | ssl_established = true; | ||
| 221 | } | ||
| 192 | #endif | 222 | #endif |
| 193 | 223 | ||
| 194 | /* watch for the SMTP connection string and */ | 224 | /* watch for the SMTP connection string and */ |
| 195 | /* return a WARNING status if we couldn't read any data */ | 225 | /* return a WARNING status if we couldn't read any data */ |
| 196 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { | 226 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { |
| 197 | printf(_("recv() failed\n")); | 227 | mp_subcheck sc_read_data = mp_subcheck_init(); |
| 198 | exit(STATE_WARNING); | 228 | sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING); |
| 199 | } | 229 | xasprintf(&sc_read_data.output, "recv() failed"); |
| 230 | mp_add_subcheck_to_check(&overall, sc_read_data); | ||
| 231 | mp_exit(overall); | ||
| 232 | } | ||
| 200 | 233 | ||
| 201 | char *server_response = NULL; | 234 | char *server_response = NULL; |
| 202 | /* save connect return (220 hostname ..) for later use */ | 235 | /* save connect return (220 hostname ..) for later use */ |
| 203 | xasprintf(&server_response, "%s", buffer); | 236 | xasprintf(&server_response, "%s", buffer); |
| 204 | 237 | ||
| 205 | /* send the HELO/EHLO command */ | 238 | /* send the HELO/EHLO command */ |
| 206 | my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established); | 239 | my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established); |
| 207 | 240 | ||
| 208 | /* allow for response to helo command to reach us */ | 241 | /* allow for response to helo command to reach us */ |
| 209 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { | 242 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { |
| 210 | printf(_("recv() failed\n")); | 243 | mp_subcheck sc_read_data = mp_subcheck_init(); |
| 211 | exit(STATE_WARNING); | 244 | sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING); |
| 212 | } | 245 | xasprintf(&sc_read_data.output, "recv() failed"); |
| 246 | mp_add_subcheck_to_check(&overall, sc_read_data); | ||
| 247 | mp_exit(overall); | ||
| 248 | } | ||
| 213 | 249 | ||
| 214 | bool supports_tls = false; | 250 | bool supports_tls = false; |
| 215 | if (config.use_ehlo || config.use_lhlo) { | 251 | if (config.use_ehlo || config.use_lhlo) { |
| 216 | if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) { | 252 | if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) { |
| 217 | supports_tls = true; | 253 | supports_tls = true; |
| 218 | } | ||
| 219 | } | 254 | } |
| 255 | } | ||
| 220 | 256 | ||
| 221 | if (config.use_starttls && !supports_tls) { | 257 | if (config.use_starttls && !supports_tls) { |
| 222 | printf(_("WARNING - TLS not supported by server\n")); | 258 | smtp_quit(config, buffer, socket_descriptor, ssl_established); |
| 259 | |||
| 260 | mp_subcheck sc_read_data = mp_subcheck_init(); | ||
| 261 | sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING); | ||
| 262 | xasprintf(&sc_read_data.output, "StartTLS not supported by server"); | ||
| 263 | mp_add_subcheck_to_check(&overall, sc_read_data); | ||
| 264 | mp_exit(overall); | ||
| 265 | } | ||
| 266 | |||
| 267 | #ifdef HAVE_SSL | ||
| 268 | if (config.use_starttls) { | ||
| 269 | /* send the STARTTLS command */ | ||
| 270 | send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); | ||
| 271 | |||
| 272 | mp_subcheck sc_starttls_init = mp_subcheck_init(); | ||
| 273 | recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 274 | ssl_established); /* wait for it */ | ||
| 275 | if (!strstr(buffer, SMTP_EXPECT)) { | ||
| 223 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | 276 | smtp_quit(config, buffer, socket_descriptor, ssl_established); |
| 224 | exit(STATE_WARNING); | 277 | |
| 278 | xasprintf(&sc_starttls_init.output, "StartTLS not supported by server"); | ||
| 279 | sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_UNKNOWN); | ||
| 280 | mp_add_subcheck_to_check(&overall, sc_starttls_init); | ||
| 281 | mp_exit(overall); | ||
| 225 | } | 282 | } |
| 226 | 283 | ||
| 227 | #ifdef HAVE_SSL | 284 | mp_state_enum starttls_result = np_net_ssl_init_with_hostname( |
| 228 | if (config.use_starttls) { | 285 | socket_descriptor, (config.use_sni ? config.server_address : NULL)); |
| 229 | /* send the STARTTLS command */ | 286 | if (starttls_result != STATE_OK) { |
| 230 | send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); | 287 | close(socket_descriptor); |
| 231 | 288 | np_net_ssl_cleanup(); | |
| 232 | recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 233 | ssl_established); /* wait for it */ | ||
| 234 | if (!strstr(buffer, SMTP_EXPECT)) { | ||
| 235 | printf(_("Server does not support STARTTLS\n")); | ||
| 236 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | ||
| 237 | exit(STATE_UNKNOWN); | ||
| 238 | } | ||
| 239 | 289 | ||
| 240 | result = np_net_ssl_init_with_hostname(socket_descriptor, | 290 | sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_CRITICAL); |
| 241 | (config.use_sni ? config.server_address : NULL)); | 291 | xasprintf(&sc_starttls_init.output, "failed to create StartTLS context"); |
| 242 | if (result != STATE_OK) { | 292 | mp_add_subcheck_to_check(&overall, sc_starttls_init); |
| 243 | printf(_("CRITICAL - Cannot create SSL context.\n")); | 293 | mp_exit(overall); |
| 244 | close(socket_descriptor); | 294 | } |
| 245 | np_net_ssl_cleanup(); | 295 | sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_OK); |
| 246 | exit(STATE_CRITICAL); | 296 | xasprintf(&sc_starttls_init.output, "created StartTLS context"); |
| 247 | } | 297 | mp_add_subcheck_to_check(&overall, sc_starttls_init); |
| 298 | |||
| 299 | ssl_established = true; | ||
| 300 | |||
| 301 | /* | ||
| 302 | * Resend the EHLO command. | ||
| 303 | * | ||
| 304 | * RFC 3207 (4.2) says: ``The client MUST discard any knowledge | ||
| 305 | * obtained from the server, such as the list of SMTP service | ||
| 306 | * extensions, which was not obtained from the TLS negotiation | ||
| 307 | * itself. The client SHOULD send an EHLO command as the first | ||
| 308 | * command after a successful TLS negotiation.'' For this | ||
| 309 | * reason, some MTAs will not allow an AUTH LOGIN command before | ||
| 310 | * we resent EHLO via TLS. | ||
| 311 | */ | ||
| 312 | if (my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established) <= | ||
| 313 | 0) { | ||
| 314 | my_close(socket_descriptor); | ||
| 315 | |||
| 316 | mp_subcheck sc_ehlo = mp_subcheck_init(); | ||
| 317 | sc_ehlo = mp_set_subcheck_state(sc_ehlo, STATE_UNKNOWN); | ||
| 318 | xasprintf(&sc_ehlo.output, "cannot send EHLO command via StartTLS"); | ||
| 319 | mp_add_subcheck_to_check(&overall, sc_ehlo); | ||
| 320 | mp_exit(overall); | ||
| 321 | } | ||
| 248 | 322 | ||
| 249 | ssl_established = true; | 323 | if (verbose) { |
| 250 | 324 | printf(_("sent %s"), helocmd); | |
| 251 | /* | 325 | } |
| 252 | * Resend the EHLO command. | ||
| 253 | * | ||
| 254 | * RFC 3207 (4.2) says: ``The client MUST discard any knowledge | ||
| 255 | * obtained from the server, such as the list of SMTP service | ||
| 256 | * extensions, which was not obtained from the TLS negotiation | ||
| 257 | * itself. The client SHOULD send an EHLO command as the first | ||
| 258 | * command after a successful TLS negotiation.'' For this | ||
| 259 | * reason, some MTAs will not allow an AUTH LOGIN command before | ||
| 260 | * we resent EHLO via TLS. | ||
| 261 | */ | ||
| 262 | if (my_send(config, helocmd, strlen(helocmd), socket_descriptor, ssl_established) <= | ||
| 263 | 0) { | ||
| 264 | printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS.")); | ||
| 265 | my_close(socket_descriptor); | ||
| 266 | exit(STATE_UNKNOWN); | ||
| 267 | } | ||
| 268 | 326 | ||
| 269 | if (verbose) { | 327 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { |
| 270 | printf(_("sent %s"), helocmd); | 328 | my_close(socket_descriptor); |
| 271 | } | ||
| 272 | 329 | ||
| 273 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= | 330 | mp_subcheck sc_ehlo = mp_subcheck_init(); |
| 274 | 0) { | 331 | sc_ehlo = mp_set_subcheck_state(sc_ehlo, STATE_UNKNOWN); |
| 275 | printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS.")); | 332 | xasprintf(&sc_ehlo.output, "cannot read EHLO response via StartTLS"); |
| 276 | my_close(socket_descriptor); | 333 | mp_add_subcheck_to_check(&overall, sc_ehlo); |
| 277 | exit(STATE_UNKNOWN); | 334 | mp_exit(overall); |
| 278 | } | 335 | } |
| 279 | 336 | ||
| 280 | if (verbose) { | 337 | if (verbose) { |
| 281 | printf("%s", buffer); | 338 | printf("%s", buffer); |
| 282 | } | 339 | } |
| 340 | } | ||
| 283 | 341 | ||
| 284 | # ifdef USE_OPENSSL | 342 | # ifdef USE_OPENSSL |
| 285 | if (config.check_cert) { | 343 | if (ssl_established) { |
| 286 | result = | 344 | net_ssl_check_cert_result cert_check_result = |
| 287 | np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit); | 345 | np_net_ssl_check_cert2(config.days_till_exp_warn, config.days_till_exp_crit); |
| 288 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | 346 | |
| 289 | my_close(socket_descriptor); | 347 | mp_subcheck sc_cert_check = mp_subcheck_init(); |
| 290 | exit(result); | 348 | |
| 349 | switch (cert_check_result.errors) { | ||
| 350 | case ALL_OK: { | ||
| 351 | |||
| 352 | if (cert_check_result.result_state != STATE_OK && | ||
| 353 | config.ignore_certificate_expiration) { | ||
| 354 | xasprintf(&sc_cert_check.output, | ||
| 355 | "Remaining certificate lifetime: %d days. Expiration will be ignored", | ||
| 356 | (int)(cert_check_result.remaining_seconds / 86400)); | ||
| 357 | sc_cert_check = mp_set_subcheck_state(sc_cert_check, STATE_OK); | ||
| 358 | } else { | ||
| 359 | xasprintf(&sc_cert_check.output, "Remaining certificate lifetime: %d days", | ||
| 360 | (int)(cert_check_result.remaining_seconds / 86400)); | ||
| 361 | sc_cert_check = | ||
| 362 | mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state); | ||
| 291 | } | 363 | } |
| 364 | } break; | ||
| 365 | case NO_SERVER_CERTIFICATE_PRESENT: { | ||
| 366 | xasprintf(&sc_cert_check.output, "no server certificate present"); | ||
| 367 | sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state); | ||
| 368 | } break; | ||
| 369 | case UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT: { | ||
| 370 | xasprintf(&sc_cert_check.output, "can not retrieve certificate subject"); | ||
| 371 | sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state); | ||
| 372 | } break; | ||
| 373 | case WRONG_TIME_FORMAT_IN_CERTIFICATE: { | ||
| 374 | xasprintf(&sc_cert_check.output, "wrong time format in certificate"); | ||
| 375 | sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state); | ||
| 376 | } break; | ||
| 377 | }; | ||
| 378 | |||
| 379 | mp_add_subcheck_to_check(&overall, sc_cert_check); | ||
| 380 | } | ||
| 292 | # endif /* USE_OPENSSL */ | 381 | # endif /* USE_OPENSSL */ |
| 293 | } | 382 | |
| 294 | #endif | 383 | #endif |
| 295 | 384 | ||
| 296 | if (verbose) { | 385 | if (verbose) { |
| 386 | printf("%s", buffer); | ||
| 387 | } | ||
| 388 | |||
| 389 | /* save buffer for later use */ | ||
| 390 | xasprintf(&server_response, "%s%s", server_response, buffer); | ||
| 391 | /* strip the buffer of carriage returns */ | ||
| 392 | strip(server_response); | ||
| 393 | |||
| 394 | /* make sure we find the droids we are looking for */ | ||
| 395 | mp_subcheck sc_expect_response = mp_subcheck_init(); | ||
| 396 | |||
| 397 | if (!strstr(server_response, config.server_expect)) { | ||
| 398 | sc_expect_response = mp_set_subcheck_state(sc_expect_response, STATE_WARNING); | ||
| 399 | if (config.server_port == SMTP_PORT) { | ||
| 400 | xasprintf(&sc_expect_response.output, _("invalid SMTP response received from host: %s"), | ||
| 401 | server_response); | ||
| 402 | } else { | ||
| 403 | xasprintf(&sc_expect_response.output, | ||
| 404 | _("invalid SMTP response received from host on port %d: %s"), | ||
| 405 | config.server_port, server_response); | ||
| 406 | } | ||
| 407 | exit(STATE_WARNING); | ||
| 408 | } else { | ||
| 409 | xasprintf(&sc_expect_response.output, "received valid SMTP response '%s' from host: '%s'", | ||
| 410 | config.server_expect, server_response); | ||
| 411 | sc_expect_response = mp_set_subcheck_state(sc_expect_response, STATE_OK); | ||
| 412 | } | ||
| 413 | |||
| 414 | mp_add_subcheck_to_check(&overall, sc_expect_response); | ||
| 415 | |||
| 416 | if (config.send_mail_from) { | ||
| 417 | my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); | ||
| 418 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && | ||
| 419 | verbose) { | ||
| 297 | printf("%s", buffer); | 420 | printf("%s", buffer); |
| 298 | } | 421 | } |
| 422 | } | ||
| 299 | 423 | ||
| 300 | /* save buffer for later use */ | 424 | size_t counter = 0; |
| 301 | xasprintf(&server_response, "%s%s", server_response, buffer); | 425 | while (counter < config.ncommands) { |
| 302 | /* strip the buffer of carriage returns */ | 426 | xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n"); |
| 303 | strip(server_response); | 427 | my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); |
| 428 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && | ||
| 429 | verbose) { | ||
| 430 | printf("%s", buffer); | ||
| 431 | } | ||
| 304 | 432 | ||
| 305 | /* make sure we find the droids we are looking for */ | 433 | strip(buffer); |
| 306 | if (!strstr(server_response, config.server_expect)) { | 434 | |
| 307 | if (config.server_port == SMTP_PORT) { | 435 | if (counter < config.nresponses) { |
| 308 | printf(_("Invalid SMTP response received from host: %s\n"), server_response); | 436 | int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; |
| 309 | } else { | 437 | regex_t preg; |
| 310 | printf(_("Invalid SMTP response received from host on port %d: %s\n"), | 438 | int errcode = regcomp(&preg, config.responses[counter], cflags); |
| 311 | config.server_port, server_response); | 439 | char errbuf[MAX_INPUT_BUFFER]; |
| 440 | if (errcode != 0) { | ||
| 441 | regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
| 442 | printf(_("Could Not Compile Regular Expression")); | ||
| 443 | exit(STATE_UNKNOWN); | ||
| 312 | } | 444 | } |
| 313 | exit(STATE_WARNING); | ||
| 314 | } | ||
| 315 | 445 | ||
| 316 | if (config.send_mail_from) { | 446 | regmatch_t pmatch[10]; |
| 317 | my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); | 447 | int eflags = 0; |
| 318 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= | 448 | int excode = regexec(&preg, buffer, 10, pmatch, eflags); |
| 319 | 1 && | 449 | mp_subcheck sc_expected_responses = mp_subcheck_init(); |
| 320 | verbose) { | 450 | if (excode == 0) { |
| 321 | printf("%s", buffer); | 451 | xasprintf(&sc_expected_responses.output, "valid response '%s' to command '%s'", |
| 452 | buffer, config.commands[counter]); | ||
| 453 | sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_OK); | ||
| 454 | } else if (excode == REG_NOMATCH) { | ||
| 455 | sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_WARNING); | ||
| 456 | xasprintf(&sc_expected_responses.output, "invalid response '%s' to command '%s'", | ||
| 457 | buffer, config.commands[counter]); | ||
| 458 | } else { | ||
| 459 | regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
| 460 | xasprintf(&sc_expected_responses.output, "regexec execute error: %s", errbuf); | ||
| 461 | sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_UNKNOWN); | ||
| 322 | } | 462 | } |
| 323 | } | 463 | } |
| 464 | counter++; | ||
| 465 | } | ||
| 324 | 466 | ||
| 325 | int counter = 0; | 467 | if (config.authtype != NULL) { |
| 326 | while (counter < config.ncommands) { | 468 | mp_subcheck sc_auth = mp_subcheck_init(); |
| 327 | xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n"); | 469 | |
| 328 | my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); | 470 | if (strcmp(config.authtype, "LOGIN") == 0) { |
| 329 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= | 471 | char *abuf; |
| 330 | 1 && | 472 | int ret; |
| 331 | verbose) { | 473 | do { |
| 332 | printf("%s", buffer); | 474 | /* send AUTH LOGIN */ |
| 333 | } | 475 | my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor, |
| 334 | strip(buffer); | 476 | ssl_established); |
| 335 | if (counter < config.nresponses) { | 477 | |
| 336 | int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; | 478 | if (verbose) { |
| 337 | regex_t preg; | 479 | printf(_("sent %s\n"), "AUTH LOGIN"); |
| 338 | int errcode = regcomp(&preg, config.responses[counter], cflags); | ||
| 339 | char errbuf[MAX_INPUT_BUFFER]; | ||
| 340 | if (errcode != 0) { | ||
| 341 | regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
| 342 | printf(_("Could Not Compile Regular Expression")); | ||
| 343 | exit(STATE_UNKNOWN); | ||
| 344 | } | 480 | } |
| 345 | 481 | ||
| 346 | regmatch_t pmatch[10]; | 482 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, |
| 347 | int eflags = 0; | 483 | ssl_established)) <= 0) { |
| 348 | int excode = regexec(&preg, buffer, 10, pmatch, eflags); | 484 | xasprintf(&sc_auth.output, _("recv() failed after AUTH LOGIN")); |
| 349 | if (excode == 0) { | 485 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_WARNING); |
| 350 | result = STATE_OK; | 486 | break; |
| 351 | } else if (excode == REG_NOMATCH) { | ||
| 352 | result = STATE_WARNING; | ||
| 353 | printf(_("SMTP %s - Invalid response '%s' to command '%s'\n"), | ||
| 354 | state_text(result), buffer, config.commands[counter]); | ||
| 355 | } else { | ||
| 356 | regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
| 357 | printf(_("Execute Error: %s\n"), errbuf); | ||
| 358 | result = STATE_UNKNOWN; | ||
| 359 | } | 487 | } |
| 360 | } | ||
| 361 | counter++; | ||
| 362 | } | ||
| 363 | 488 | ||
| 364 | if (config.authtype != NULL) { | 489 | if (verbose) { |
| 365 | if (strcmp(config.authtype, "LOGIN") == 0) { | 490 | printf(_("received %s\n"), buffer); |
| 366 | char *abuf; | 491 | } |
| 367 | int ret; | 492 | |
| 368 | do { | 493 | if (strncmp(buffer, "334", 3) != 0) { |
| 369 | if (config.authuser == NULL) { | 494 | xasprintf(&sc_auth.output, "invalid response received after AUTH LOGIN"); |
| 370 | result = STATE_CRITICAL; | 495 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); |
| 371 | xasprintf(&error_msg, _("no authuser specified, ")); | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | if (config.authpass == NULL) { | ||
| 375 | result = STATE_CRITICAL; | ||
| 376 | xasprintf(&error_msg, _("no authpass specified, ")); | ||
| 377 | break; | ||
| 378 | } | ||
| 379 | |||
| 380 | /* send AUTH LOGIN */ | ||
| 381 | my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor, | ||
| 382 | ssl_established); | ||
| 383 | if (verbose) { | ||
| 384 | printf(_("sent %s\n"), "AUTH LOGIN"); | ||
| 385 | } | ||
| 386 | |||
| 387 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 388 | ssl_established)) <= 0) { | ||
| 389 | xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, ")); | ||
| 390 | result = STATE_WARNING; | ||
| 391 | break; | ||
| 392 | } | ||
| 393 | if (verbose) { | ||
| 394 | printf(_("received %s\n"), buffer); | ||
| 395 | } | ||
| 396 | |||
| 397 | if (strncmp(buffer, "334", 3) != 0) { | ||
| 398 | result = STATE_CRITICAL; | ||
| 399 | xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, ")); | ||
| 400 | break; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* encode authuser with base64 */ | ||
| 404 | base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf); | ||
| 405 | xasprintf(&abuf, "%s\r\n", abuf); | ||
| 406 | my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established); | ||
| 407 | if (verbose) { | ||
| 408 | printf(_("sent %s\n"), abuf); | ||
| 409 | } | ||
| 410 | |||
| 411 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 412 | ssl_established)) <= 0) { | ||
| 413 | result = STATE_CRITICAL; | ||
| 414 | xasprintf(&error_msg, _("recv() failed after sending authuser, ")); | ||
| 415 | break; | ||
| 416 | } | ||
| 417 | if (verbose) { | ||
| 418 | printf(_("received %s\n"), buffer); | ||
| 419 | } | ||
| 420 | if (strncmp(buffer, "334", 3) != 0) { | ||
| 421 | result = STATE_CRITICAL; | ||
| 422 | xasprintf(&error_msg, _("invalid response received after authuser, ")); | ||
| 423 | break; | ||
| 424 | } | ||
| 425 | /* encode authpass with base64 */ | ||
| 426 | base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf); | ||
| 427 | xasprintf(&abuf, "%s\r\n", abuf); | ||
| 428 | my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established); | ||
| 429 | if (verbose) { | ||
| 430 | printf(_("sent %s\n"), abuf); | ||
| 431 | } | ||
| 432 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 433 | ssl_established)) <= 0) { | ||
| 434 | result = STATE_CRITICAL; | ||
| 435 | xasprintf(&error_msg, _("recv() failed after sending authpass, ")); | ||
| 436 | break; | ||
| 437 | } | ||
| 438 | if (verbose) { | ||
| 439 | printf(_("received %s\n"), buffer); | ||
| 440 | } | ||
| 441 | if (strncmp(buffer, "235", 3) != 0) { | ||
| 442 | result = STATE_CRITICAL; | ||
| 443 | xasprintf(&error_msg, _("invalid response received after authpass, ")); | ||
| 444 | break; | ||
| 445 | } | ||
| 446 | break; | 496 | break; |
| 447 | } while (false); | 497 | } |
| 448 | } else { | ||
| 449 | result = STATE_CRITICAL; | ||
| 450 | xasprintf(&error_msg, _("only authtype LOGIN is supported, ")); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | 498 | ||
| 454 | /* tell the server we're done */ | 499 | /* encode authuser with base64 */ |
| 455 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | 500 | base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf); |
| 501 | xasprintf(&abuf, "%s\r\n", abuf); | ||
| 502 | my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established); | ||
| 503 | if (verbose) { | ||
| 504 | printf(_("sent %s\n"), abuf); | ||
| 505 | } | ||
| 506 | |||
| 507 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 508 | ssl_established)) <= 0) { | ||
| 509 | xasprintf(&sc_auth.output, "recv() failed after sending authuser"); | ||
| 510 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 511 | break; | ||
| 512 | } | ||
| 513 | |||
| 514 | if (verbose) { | ||
| 515 | printf(_("received %s\n"), buffer); | ||
| 516 | } | ||
| 517 | |||
| 518 | if (strncmp(buffer, "334", 3) != 0) { | ||
| 519 | xasprintf(&sc_auth.output, "invalid response received after authuser"); | ||
| 520 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 521 | break; | ||
| 522 | } | ||
| 456 | 523 | ||
| 457 | /* finally close the connection */ | 524 | /* encode authpass with base64 */ |
| 458 | close(socket_descriptor); | 525 | base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf); |
| 526 | xasprintf(&abuf, "%s\r\n", abuf); | ||
| 527 | my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established); | ||
| 528 | |||
| 529 | if (verbose) { | ||
| 530 | printf(_("sent %s\n"), abuf); | ||
| 531 | } | ||
| 532 | |||
| 533 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 534 | ssl_established)) <= 0) { | ||
| 535 | xasprintf(&sc_auth.output, "recv() failed after sending authpass"); | ||
| 536 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 537 | break; | ||
| 538 | } | ||
| 539 | |||
| 540 | if (verbose) { | ||
| 541 | printf(_("received %s\n"), buffer); | ||
| 542 | } | ||
| 543 | |||
| 544 | if (strncmp(buffer, "235", 3) != 0) { | ||
| 545 | xasprintf(&sc_auth.output, "invalid response received after authpass"); | ||
| 546 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 547 | break; | ||
| 548 | } | ||
| 549 | break; | ||
| 550 | } while (false); | ||
| 551 | } else { | ||
| 552 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 553 | xasprintf(&sc_auth.output, "only authtype LOGIN is supported"); | ||
| 554 | } | ||
| 555 | |||
| 556 | mp_add_subcheck_to_check(&overall, sc_auth); | ||
| 459 | } | 557 | } |
| 460 | 558 | ||
| 559 | /* tell the server we're done */ | ||
| 560 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | ||
| 561 | |||
| 562 | /* finally close the connection */ | ||
| 563 | close(socket_descriptor); | ||
| 564 | |||
| 461 | /* reset the alarm */ | 565 | /* reset the alarm */ |
| 462 | alarm(0); | 566 | alarm(0); |
| 463 | 567 | ||
| 464 | long microsec = deltime(start_time); | 568 | long microsec = deltime(start_time); |
| 465 | double elapsed_time = (double)microsec / 1.0e6; | 569 | double elapsed_time = (double)microsec / 1.0e6; |
| 466 | 570 | ||
| 467 | if (result == STATE_OK) { | 571 | mp_perfdata pd_elapsed_time = perfdata_init(); |
| 468 | if (config.check_critical_time && elapsed_time > config.critical_time) { | 572 | pd_elapsed_time = mp_set_pd_value(pd_elapsed_time, elapsed_time); |
| 469 | result = STATE_CRITICAL; | 573 | pd_elapsed_time.label = "time"; |
| 470 | } else if (config.check_warning_time && elapsed_time > config.warning_time) { | 574 | pd_elapsed_time.uom = "s"; |
| 471 | result = STATE_WARNING; | 575 | |
| 472 | } | 576 | pd_elapsed_time = mp_pd_set_thresholds(pd_elapsed_time, config.connection_time); |
| 473 | } | ||
| 474 | 577 | ||
| 475 | printf(_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), state_text(result), error_msg, | 578 | mp_subcheck sc_connection_time = mp_subcheck_init(); |
| 476 | elapsed_time, verbose ? ", " : "", verbose ? buffer : "", | 579 | xasprintf(&sc_connection_time.output, "connection time: %.3gs", elapsed_time); |
| 477 | fperfdata("time", elapsed_time, "s", config.check_warning_time, config.warning_time, | 580 | sc_connection_time = |
| 478 | config.check_critical_time, config.critical_time, true, 0, false, 0)); | 581 | mp_set_subcheck_state(sc_connection_time, mp_get_pd_status(pd_elapsed_time)); |
| 582 | mp_add_subcheck_to_check(&overall, sc_connection_time); | ||
| 479 | 583 | ||
| 480 | exit(result); | 584 | mp_exit(overall); |
| 481 | } | 585 | } |
| 482 | 586 | ||
| 483 | /* process command-line arguments */ | 587 | /* process command-line arguments */ |
| 484 | check_smtp_config_wrapper process_arguments(int argc, char **argv) { | 588 | check_smtp_config_wrapper process_arguments(int argc, char **argv) { |
| 485 | enum { | 589 | enum { |
| 486 | SNI_OPTION = CHAR_MAX + 1 | 590 | SNI_OPTION = CHAR_MAX + 1, |
| 591 | output_format_index, | ||
| 592 | ignore_certificate_expiration_index, | ||
| 487 | }; | 593 | }; |
| 488 | 594 | ||
| 489 | int option = 0; | 595 | int option = 0; |
| 490 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, | 596 | static struct option longopts[] = { |
| 491 | {"expect", required_argument, 0, 'e'}, | 597 | {"hostname", required_argument, 0, 'H'}, |
| 492 | {"critical", required_argument, 0, 'c'}, | 598 | {"expect", required_argument, 0, 'e'}, |
| 493 | {"warning", required_argument, 0, 'w'}, | 599 | {"critical", required_argument, 0, 'c'}, |
| 494 | {"timeout", required_argument, 0, 't'}, | 600 | {"warning", required_argument, 0, 'w'}, |
| 495 | {"port", required_argument, 0, 'p'}, | 601 | {"timeout", required_argument, 0, 't'}, |
| 496 | {"from", required_argument, 0, 'f'}, | 602 | {"port", required_argument, 0, 'p'}, |
| 497 | {"fqdn", required_argument, 0, 'F'}, | 603 | {"from", required_argument, 0, 'f'}, |
| 498 | {"authtype", required_argument, 0, 'A'}, | 604 | {"fqdn", required_argument, 0, 'F'}, |
| 499 | {"authuser", required_argument, 0, 'U'}, | 605 | {"authtype", required_argument, 0, 'A'}, |
| 500 | {"authpass", required_argument, 0, 'P'}, | 606 | {"authuser", required_argument, 0, 'U'}, |
| 501 | {"command", required_argument, 0, 'C'}, | 607 | {"authpass", required_argument, 0, 'P'}, |
| 502 | {"response", required_argument, 0, 'R'}, | 608 | {"command", required_argument, 0, 'C'}, |
| 503 | {"verbose", no_argument, 0, 'v'}, | 609 | {"response", required_argument, 0, 'R'}, |
| 504 | {"version", no_argument, 0, 'V'}, | 610 | {"verbose", no_argument, 0, 'v'}, |
| 505 | {"use-ipv4", no_argument, 0, '4'}, | 611 | {"version", no_argument, 0, 'V'}, |
| 506 | {"use-ipv6", no_argument, 0, '6'}, | 612 | {"use-ipv4", no_argument, 0, '4'}, |
| 507 | {"help", no_argument, 0, 'h'}, | 613 | {"use-ipv6", no_argument, 0, '6'}, |
| 508 | {"lmtp", no_argument, 0, 'L'}, | 614 | {"help", no_argument, 0, 'h'}, |
| 509 | {"ssl", no_argument, 0, 's'}, | 615 | {"lmtp", no_argument, 0, 'L'}, |
| 510 | {"tls", no_argument, 0, 's'}, | 616 | {"ssl", no_argument, 0, 's'}, |
| 511 | {"starttls", no_argument, 0, 'S'}, | 617 | {"tls", no_argument, 0, 's'}, |
| 512 | {"sni", no_argument, 0, SNI_OPTION}, | 618 | {"starttls", no_argument, 0, 'S'}, |
| 513 | {"certificate", required_argument, 0, 'D'}, | 619 | {"sni", no_argument, 0, SNI_OPTION}, |
| 514 | {"ignore-quit-failure", no_argument, 0, 'q'}, | 620 | {"certificate", required_argument, 0, 'D'}, |
| 515 | {"proxy", no_argument, 0, 'r'}, | 621 | {"ignore-quit-failure", no_argument, 0, 'q'}, |
| 516 | {0, 0, 0, 0}}; | 622 | {"proxy", no_argument, 0, 'r'}, |
| 623 | {"ignore-certificate-expiration", no_argument, 0, ignore_certificate_expiration_index}, | ||
| 624 | {"output-format", required_argument, 0, output_format_index}, | ||
| 625 | {0, 0, 0, 0}}; | ||
| 517 | 626 | ||
| 518 | check_smtp_config_wrapper result = { | 627 | check_smtp_config_wrapper result = { |
| 519 | .config = check_smtp_config_init(), | 628 | .config = check_smtp_config_init(), |
| @@ -535,8 +644,8 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 535 | } | 644 | } |
| 536 | } | 645 | } |
| 537 | 646 | ||
| 538 | int command_size = 0; | 647 | unsigned long command_size = 0; |
| 539 | int response_size = 0; | 648 | unsigned long response_size = 0; |
| 540 | bool implicit_tls = false; | 649 | bool implicit_tls = false; |
| 541 | int server_port_option = 0; | 650 | int server_port_option = 0; |
| 542 | while (true) { | 651 | while (true) { |
| @@ -591,7 +700,7 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 591 | result.config.commands = | 700 | result.config.commands = |
| 592 | realloc(result.config.commands, sizeof(char *) * command_size); | 701 | realloc(result.config.commands, sizeof(char *) * command_size); |
| 593 | if (result.config.commands == NULL) { | 702 | if (result.config.commands == NULL) { |
| 594 | die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), | 703 | die(STATE_UNKNOWN, _("Could not realloc() units [%lu]\n"), |
| 595 | result.config.ncommands); | 704 | result.config.ncommands); |
| 596 | } | 705 | } |
| 597 | } | 706 | } |
| @@ -605,7 +714,7 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 605 | result.config.responses = | 714 | result.config.responses = |
| 606 | realloc(result.config.responses, sizeof(char *) * response_size); | 715 | realloc(result.config.responses, sizeof(char *) * response_size); |
| 607 | if (result.config.responses == NULL) { | 716 | if (result.config.responses == NULL) { |
| 608 | die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), | 717 | die(STATE_UNKNOWN, _("Could not realloc() units [%lu]\n"), |
| 609 | result.config.nresponses); | 718 | result.config.nresponses); |
| 610 | } | 719 | } |
| 611 | } | 720 | } |
| @@ -613,22 +722,22 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 613 | strncpy(result.config.responses[result.config.nresponses], optarg, 255); | 722 | strncpy(result.config.responses[result.config.nresponses], optarg, 255); |
| 614 | result.config.nresponses++; | 723 | result.config.nresponses++; |
| 615 | break; | 724 | break; |
| 616 | case 'c': /* critical time threshold */ | 725 | case 'c': /* critical time threshold */ { |
| 617 | if (!is_nonnegative(optarg)) { | 726 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 618 | usage4(_("Critical time must be a positive")); | 727 | if (tmp.error != MP_PARSING_SUCCES) { |
| 619 | } else { | 728 | die(STATE_UNKNOWN, "failed to parse critical time threshold"); |
| 620 | result.config.critical_time = strtod(optarg, NULL); | ||
| 621 | result.config.check_critical_time = true; | ||
| 622 | } | 729 | } |
| 623 | break; | 730 | result.config.connection_time = |
| 624 | case 'w': /* warning time threshold */ | 731 | mp_thresholds_set_warn(result.config.connection_time, tmp.range); |
| 625 | if (!is_nonnegative(optarg)) { | 732 | } break; |
| 626 | usage4(_("Warning time must be a positive")); | 733 | case 'w': /* warning time threshold */ { |
| 627 | } else { | 734 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 628 | result.config.warning_time = strtod(optarg, NULL); | 735 | if (tmp.error != MP_PARSING_SUCCES) { |
| 629 | result.config.check_warning_time = true; | 736 | die(STATE_UNKNOWN, "failed to parse warning time threshold"); |
| 630 | } | 737 | } |
| 631 | break; | 738 | result.config.connection_time = |
| 739 | mp_thresholds_set_crit(result.config.connection_time, tmp.range); | ||
| 740 | } break; | ||
| 632 | case 'v': /* verbose */ | 741 | case 'v': /* verbose */ |
| 633 | verbose++; | 742 | verbose++; |
| 634 | break; | 743 | break; |
| @@ -665,7 +774,6 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 665 | } | 774 | } |
| 666 | result.config.days_till_exp_warn = atoi(optarg); | 775 | result.config.days_till_exp_warn = atoi(optarg); |
| 667 | } | 776 | } |
| 668 | result.config.check_cert = true; | ||
| 669 | result.config.ignore_send_quit_failure = true; | 777 | result.config.ignore_send_quit_failure = true; |
| 670 | #else | 778 | #else |
| 671 | usage(_("SSL support not available - install OpenSSL and recompile")); | 779 | usage(_("SSL support not available - install OpenSSL and recompile")); |
| @@ -714,6 +822,21 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 714 | exit(STATE_UNKNOWN); | 822 | exit(STATE_UNKNOWN); |
| 715 | case '?': /* help */ | 823 | case '?': /* help */ |
| 716 | usage5(); | 824 | usage5(); |
| 825 | case output_format_index: { | ||
| 826 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 827 | if (!parser.parsing_success) { | ||
| 828 | // TODO List all available formats here, maybe add anothoer usage function | ||
| 829 | printf("Invalid output format: %s\n", optarg); | ||
| 830 | exit(STATE_UNKNOWN); | ||
| 831 | } | ||
| 832 | |||
| 833 | result.config.output_format_is_set = true; | ||
| 834 | result.config.output_format = parser.output_format; | ||
| 835 | break; | ||
| 836 | } | ||
| 837 | case ignore_certificate_expiration_index: { | ||
| 838 | result.config.ignore_certificate_expiration = true; | ||
| 839 | } | ||
| 717 | } | 840 | } |
| 718 | } | 841 | } |
| 719 | 842 | ||
| @@ -742,6 +865,19 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 742 | result.config.server_port = server_port_option; | 865 | result.config.server_port = server_port_option; |
| 743 | } | 866 | } |
| 744 | 867 | ||
| 868 | if (result.config.authtype) { | ||
| 869 | if (strcmp(result.config.authtype, "LOGIN") == 0) { | ||
| 870 | if (result.config.authuser == NULL) { | ||
| 871 | usage4("no authuser specified"); | ||
| 872 | } | ||
| 873 | if (result.config.authpass == NULL) { | ||
| 874 | usage4("no authpass specified"); | ||
| 875 | } | ||
| 876 | } else { | ||
| 877 | usage4("only authtype LOGIN is supported"); | ||
| 878 | } | ||
| 879 | } | ||
| 880 | |||
| 745 | return result; | 881 | return result; |
| 746 | } | 882 | } |
| 747 | 883 | ||
| @@ -791,7 +927,7 @@ char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int soc | |||
| 791 | int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor, | 927 | int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor, |
| 792 | bool ssl_established) { | 928 | bool ssl_established) { |
| 793 | int result; | 929 | int result; |
| 794 | int counter; | 930 | size_t counter; |
| 795 | 931 | ||
| 796 | for (counter = result = 0; counter < bufsize - 1; counter++) { | 932 | for (counter = result = 0; counter < bufsize - 1; counter++) { |
| 797 | if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) { | 933 | if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) { |
| @@ -799,7 +935,7 @@ int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_des | |||
| 799 | } | 935 | } |
| 800 | if (buf[counter] == '\n') { | 936 | if (buf[counter] == '\n') { |
| 801 | buf[++counter] = '\0'; | 937 | buf[++counter] = '\0'; |
| 802 | return counter; | 938 | return (int)counter; |
| 803 | } | 939 | } |
| 804 | } | 940 | } |
| 805 | return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */ | 941 | return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */ |
| @@ -902,11 +1038,15 @@ void print_help(void) { | |||
| 902 | printf(" %s\n", _("Send LHLO instead of HELO/EHLO")); | 1038 | printf(" %s\n", _("Send LHLO instead of HELO/EHLO")); |
| 903 | printf(" %s\n", "-q, --ignore-quit-failure"); | 1039 | printf(" %s\n", "-q, --ignore-quit-failure"); |
| 904 | printf(" %s\n", _("Ignore failure when sending QUIT command to server")); | 1040 | printf(" %s\n", _("Ignore failure when sending QUIT command to server")); |
| 1041 | printf(" %s\n", "--ignore-certificate-expiration"); | ||
| 1042 | printf(" %s\n", _("Ignore certificate expiration")); | ||
| 905 | 1043 | ||
| 906 | printf(UT_WARN_CRIT); | 1044 | printf(UT_WARN_CRIT); |
| 907 | 1045 | ||
| 908 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 1046 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
| 909 | 1047 | ||
| 1048 | printf(UT_OUTPUT_FORMAT); | ||
| 1049 | |||
| 910 | printf(UT_VERBOSE); | 1050 | printf(UT_VERBOSE); |
| 911 | 1051 | ||
| 912 | printf("\n"); | 1052 | printf("\n"); |
diff --git a/plugins/check_smtp.d/config.h b/plugins/check_smtp.d/config.h index 0a6511ef..b0d42ed1 100644 --- a/plugins/check_smtp.d/config.h +++ b/plugins/check_smtp.d/config.h | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 5 | #include "thresholds.h" | ||
| 4 | #include <stddef.h> | 6 | #include <stddef.h> |
| 5 | #include <string.h> | 7 | #include <string.h> |
| 6 | 8 | ||
| @@ -18,20 +20,18 @@ typedef struct { | |||
| 18 | char *server_expect; | 20 | char *server_expect; |
| 19 | bool ignore_send_quit_failure; | 21 | bool ignore_send_quit_failure; |
| 20 | 22 | ||
| 21 | double warning_time; | 23 | mp_thresholds connection_time; |
| 22 | bool check_warning_time; | 24 | |
| 23 | double critical_time; | ||
| 24 | bool check_critical_time; | ||
| 25 | bool use_ehlo; | 25 | bool use_ehlo; |
| 26 | bool use_lhlo; | 26 | bool use_lhlo; |
| 27 | 27 | ||
| 28 | char *from_arg; | 28 | char *from_arg; |
| 29 | bool send_mail_from; | 29 | bool send_mail_from; |
| 30 | 30 | ||
| 31 | int ncommands; | 31 | unsigned long ncommands; |
| 32 | char **commands; | 32 | char **commands; |
| 33 | 33 | ||
| 34 | int nresponses; | 34 | unsigned long nresponses; |
| 35 | char **responses; | 35 | char **responses; |
| 36 | 36 | ||
| 37 | char *authtype; | 37 | char *authtype; |
| @@ -40,13 +40,17 @@ typedef struct { | |||
| 40 | 40 | ||
| 41 | bool use_proxy_prefix; | 41 | bool use_proxy_prefix; |
| 42 | #ifdef HAVE_SSL | 42 | #ifdef HAVE_SSL |
| 43 | bool check_cert; | ||
| 44 | int days_till_exp_warn; | 43 | int days_till_exp_warn; |
| 45 | int days_till_exp_crit; | 44 | int days_till_exp_crit; |
| 46 | bool use_ssl; | 45 | bool use_ssl; |
| 47 | bool use_starttls; | 46 | bool use_starttls; |
| 48 | bool use_sni; | 47 | bool use_sni; |
| 48 | |||
| 49 | bool ignore_certificate_expiration; | ||
| 49 | #endif | 50 | #endif |
| 51 | |||
| 52 | bool output_format_is_set; | ||
| 53 | mp_output_format output_format; | ||
| 50 | } check_smtp_config; | 54 | } check_smtp_config; |
| 51 | 55 | ||
| 52 | check_smtp_config check_smtp_config_init() { | 56 | check_smtp_config check_smtp_config_init() { |
| @@ -58,10 +62,7 @@ check_smtp_config check_smtp_config_init() { | |||
| 58 | .server_expect = SMTP_EXPECT, | 62 | .server_expect = SMTP_EXPECT, |
| 59 | .ignore_send_quit_failure = false, | 63 | .ignore_send_quit_failure = false, |
| 60 | 64 | ||
| 61 | .warning_time = 0, | 65 | .connection_time = mp_thresholds_init(), |
| 62 | .check_warning_time = false, | ||
| 63 | .critical_time = 0, | ||
| 64 | .check_critical_time = false, | ||
| 65 | .use_ehlo = false, | 66 | .use_ehlo = false, |
| 66 | .use_lhlo = false, | 67 | .use_lhlo = false, |
| 67 | 68 | ||
| @@ -80,13 +81,16 @@ check_smtp_config check_smtp_config_init() { | |||
| 80 | 81 | ||
| 81 | .use_proxy_prefix = false, | 82 | .use_proxy_prefix = false, |
| 82 | #ifdef HAVE_SSL | 83 | #ifdef HAVE_SSL |
| 83 | .check_cert = false, | ||
| 84 | .days_till_exp_warn = 0, | 84 | .days_till_exp_warn = 0, |
| 85 | .days_till_exp_crit = 0, | 85 | .days_till_exp_crit = 0, |
| 86 | .use_ssl = false, | 86 | .use_ssl = false, |
| 87 | .use_starttls = false, | 87 | .use_starttls = false, |
| 88 | .use_sni = false, | 88 | .use_sni = false, |
| 89 | |||
| 90 | .ignore_certificate_expiration = false, | ||
| 89 | #endif | 91 | #endif |
| 92 | |||
| 93 | .output_format_is_set = false, | ||
| 90 | }; | 94 | }; |
| 91 | return tmp; | 95 | return tmp; |
| 92 | } | 96 | } |
diff --git a/plugins/netutils.h b/plugins/netutils.h index c4461113..dbd22398 100644 --- a/plugins/netutils.h +++ b/plugins/netutils.h | |||
| @@ -114,6 +114,26 @@ int np_net_ssl_init_with_hostname_version_and_cert(int socket, char *host_name, | |||
| 114 | void np_net_ssl_cleanup(void); | 114 | void np_net_ssl_cleanup(void); |
| 115 | int np_net_ssl_write(const void *buf, int num); | 115 | int np_net_ssl_write(const void *buf, int num); |
| 116 | int np_net_ssl_read(void *buf, int num); | 116 | int np_net_ssl_read(void *buf, int num); |
| 117 | |||
| 118 | typedef enum { | ||
| 119 | ALL_OK, | ||
| 120 | NO_SERVER_CERTIFICATE_PRESENT, | ||
| 121 | UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT, | ||
| 122 | WRONG_TIME_FORMAT_IN_CERTIFICATE, | ||
| 123 | } retrieve_expiration_date_errors; | ||
| 124 | |||
| 125 | typedef struct { | ||
| 126 | double remaining_seconds; | ||
| 127 | retrieve_expiration_date_errors errors; | ||
| 128 | } retrieve_expiration_time_result; | ||
| 129 | |||
| 130 | typedef struct { | ||
| 131 | mp_state_enum result_state; | ||
| 132 | double remaining_seconds; | ||
| 133 | retrieve_expiration_date_errors errors; | ||
| 134 | } net_ssl_check_cert_result; | ||
| 135 | net_ssl_check_cert_result np_net_ssl_check_cert2(int days_till_exp_warn, int days_till_exp_crit); | ||
| 136 | |||
| 117 | mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); | 137 | mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); |
| 118 | mp_subcheck mp_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); | 138 | mp_subcheck mp_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); |
| 119 | #endif /* HAVE_SSL */ | 139 | #endif /* HAVE_SSL */ |
diff --git a/plugins/runcmd.c b/plugins/runcmd.c index 7c583b85..be6691d2 100644 --- a/plugins/runcmd.c +++ b/plugins/runcmd.c | |||
| @@ -300,7 +300,6 @@ static int np_fetch_output(int fd, output *op, int flags) { | |||
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | op->line = NULL; | 302 | op->line = NULL; |
| 303 | op->lens = NULL; | ||
| 304 | i = 0; | 303 | i = 0; |
| 305 | while (i < op->buflen) { | 304 | while (i < op->buflen) { |
| 306 | /* make sure we have enough memory */ | 305 | /* make sure we have enough memory */ |
| @@ -311,7 +310,6 @@ static int np_fetch_output(int fd, output *op, int flags) { | |||
| 311 | } while (!ary_size); | 310 | } while (!ary_size); |
| 312 | 311 | ||
| 313 | op->line = realloc(op->line, ary_size * sizeof(char *)); | 312 | op->line = realloc(op->line, ary_size * sizeof(char *)); |
| 314 | op->lens = realloc(op->lens, ary_size * sizeof(size_t)); | ||
| 315 | } | 313 | } |
| 316 | 314 | ||
| 317 | /* set the pointer to the string */ | 315 | /* set the pointer to the string */ |
| @@ -323,9 +321,6 @@ static int np_fetch_output(int fd, output *op, int flags) { | |||
| 323 | } | 321 | } |
| 324 | buf[i] = '\0'; | 322 | buf[i] = '\0'; |
| 325 | 323 | ||
| 326 | /* calculate the string length using pointer difference */ | ||
| 327 | op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno]; | ||
| 328 | |||
| 329 | lineno++; | 324 | lineno++; |
| 330 | i++; | 325 | i++; |
| 331 | } | 326 | } |
diff --git a/plugins/sslutils.c b/plugins/sslutils.c index 0e6d7525..c58a35ab 100644 --- a/plugins/sslutils.c +++ b/plugins/sslutils.c | |||
| @@ -312,6 +312,138 @@ mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_ | |||
| 312 | # endif /* USE_OPENSSL */ | 312 | # endif /* USE_OPENSSL */ |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | retrieve_expiration_time_result np_net_ssl_get_cert_expiration(X509 *certificate) { | ||
| 316 | # ifdef USE_OPENSSL | ||
| 317 | retrieve_expiration_time_result result = { | ||
| 318 | .errors = ALL_OK, | ||
| 319 | .remaining_seconds = 0, | ||
| 320 | }; | ||
| 321 | |||
| 322 | if (!certificate) { | ||
| 323 | // printf("%s\n", _("CRITICAL - No server certificate present to inspect.")); | ||
| 324 | result.errors = NO_SERVER_CERTIFICATE_PRESENT; | ||
| 325 | return result; | ||
| 326 | } | ||
| 327 | |||
| 328 | /* Extract CN from certificate subject */ | ||
| 329 | X509_NAME *subj = X509_get_subject_name(certificate); | ||
| 330 | |||
| 331 | if (!subj) { | ||
| 332 | // printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject.")); | ||
| 333 | result.errors = UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT; | ||
| 334 | return result; | ||
| 335 | } | ||
| 336 | |||
| 337 | char cn[MAX_CN_LENGTH] = ""; | ||
| 338 | int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn)); | ||
| 339 | if (cnlen == -1) { | ||
| 340 | strcpy(cn, _("Unknown CN")); | ||
| 341 | } | ||
| 342 | |||
| 343 | /* Retrieve timestamp of certificate */ | ||
| 344 | ASN1_STRING *expiration_timestamp = X509_get_notAfter(certificate); | ||
| 345 | |||
| 346 | int offset = 0; | ||
| 347 | struct tm stamp = {}; | ||
| 348 | /* Generate tm structure to process timestamp */ | ||
| 349 | if (expiration_timestamp->type == V_ASN1_UTCTIME) { | ||
| 350 | if (expiration_timestamp->length < 10) { | ||
| 351 | result.errors = WRONG_TIME_FORMAT_IN_CERTIFICATE; | ||
| 352 | return result; | ||
| 353 | } | ||
| 354 | |||
| 355 | stamp.tm_year = | ||
| 356 | (expiration_timestamp->data[0] - '0') * 10 + (expiration_timestamp->data[1] - '0'); | ||
| 357 | if (stamp.tm_year < 50) { | ||
| 358 | stamp.tm_year += 100; | ||
| 359 | } | ||
| 360 | offset = 0; | ||
| 361 | } else { | ||
| 362 | if (expiration_timestamp->length < 12) { | ||
| 363 | result.errors = WRONG_TIME_FORMAT_IN_CERTIFICATE; | ||
| 364 | return result; | ||
| 365 | } | ||
| 366 | |||
| 367 | stamp.tm_year = (expiration_timestamp->data[0] - '0') * 1000 + | ||
| 368 | (expiration_timestamp->data[1] - '0') * 100 + | ||
| 369 | (expiration_timestamp->data[2] - '0') * 10 + | ||
| 370 | (expiration_timestamp->data[3] - '0'); | ||
| 371 | stamp.tm_year -= 1900; | ||
| 372 | offset = 2; | ||
| 373 | } | ||
| 374 | stamp.tm_mon = (expiration_timestamp->data[2 + offset] - '0') * 10 + | ||
| 375 | (expiration_timestamp->data[3 + offset] - '0') - 1; | ||
| 376 | stamp.tm_mday = (expiration_timestamp->data[4 + offset] - '0') * 10 + | ||
| 377 | (expiration_timestamp->data[5 + offset] - '0'); | ||
| 378 | stamp.tm_hour = (expiration_timestamp->data[6 + offset] - '0') * 10 + | ||
| 379 | (expiration_timestamp->data[7 + offset] - '0'); | ||
| 380 | stamp.tm_min = (expiration_timestamp->data[8 + offset] - '0') * 10 + | ||
| 381 | (expiration_timestamp->data[9 + offset] - '0'); | ||
| 382 | stamp.tm_sec = (expiration_timestamp->data[10 + offset] - '0') * 10 + | ||
| 383 | (expiration_timestamp->data[11 + offset] - '0'); | ||
| 384 | stamp.tm_isdst = -1; | ||
| 385 | |||
| 386 | time_t tm_t = timegm(&stamp); | ||
| 387 | double time_left = difftime(tm_t, time(NULL)); | ||
| 388 | result.remaining_seconds = time_left; | ||
| 389 | |||
| 390 | char *timezone = getenv("TZ"); | ||
| 391 | setenv("TZ", "GMT", 1); | ||
| 392 | tzset(); | ||
| 393 | |||
| 394 | char timestamp[50] = ""; | ||
| 395 | strftime(timestamp, 50, "%c %z", localtime(&tm_t)); | ||
| 396 | if (timezone) { | ||
| 397 | setenv("TZ", timezone, 1); | ||
| 398 | } else { | ||
| 399 | unsetenv("TZ"); | ||
| 400 | } | ||
| 401 | |||
| 402 | tzset(); | ||
| 403 | |||
| 404 | X509_free(certificate); | ||
| 405 | |||
| 406 | return result; | ||
| 407 | # else /* ifndef USE_OPENSSL */ | ||
| 408 | printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); | ||
| 409 | return STATE_WARNING; | ||
| 410 | # endif /* USE_OPENSSL */ | ||
| 411 | } | ||
| 412 | |||
| 413 | net_ssl_check_cert_result np_net_ssl_check_cert2(int days_till_exp_warn, int days_till_exp_crit) { | ||
| 414 | # ifdef USE_OPENSSL | ||
| 415 | X509 *certificate = NULL; | ||
| 416 | certificate = SSL_get_peer_certificate(s); | ||
| 417 | |||
| 418 | retrieve_expiration_time_result expiration_date = np_net_ssl_get_cert_expiration(certificate); | ||
| 419 | |||
| 420 | net_ssl_check_cert_result result = { | ||
| 421 | .result_state = STATE_UNKNOWN, | ||
| 422 | .remaining_seconds = expiration_date.remaining_seconds, | ||
| 423 | .errors = expiration_date.errors, | ||
| 424 | }; | ||
| 425 | |||
| 426 | if (expiration_date.errors == ALL_OK) { | ||
| 427 | // got a valid expiration date | ||
| 428 | unsigned int remaining_days = result.remaining_seconds / 86400; | ||
| 429 | |||
| 430 | if (remaining_days < days_till_exp_crit) { | ||
| 431 | result.result_state = STATE_CRITICAL; | ||
| 432 | } else if (remaining_days < days_till_exp_warn) { | ||
| 433 | result.result_state = STATE_WARNING; | ||
| 434 | } else { | ||
| 435 | result.result_state = STATE_OK; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | return result; | ||
| 440 | |||
| 441 | # else /* ifndef USE_OPENSSL */ | ||
| 442 | printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); | ||
| 443 | return STATE_WARNING; | ||
| 444 | # endif /* USE_OPENSSL */ | ||
| 445 | } | ||
| 446 | |||
| 315 | mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) { | 447 | mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) { |
| 316 | # ifdef USE_OPENSSL | 448 | # ifdef USE_OPENSSL |
| 317 | X509 *certificate = NULL; | 449 | X509 *certificate = NULL; |
diff --git a/plugins/t/check_by_ssh.t b/plugins/t/check_by_ssh.t index b6479f1f..0ee310cd 100644 --- a/plugins/t/check_by_ssh.t +++ b/plugins/t/check_by_ssh.t | |||
| @@ -16,7 +16,7 @@ my $ssh_conf = getTestParameter( "NP_SSH_CONFIGFILE", "A config file with ssh | |||
| 16 | 16 | ||
| 17 | plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_service && $ssh_key); | 17 | plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_service && $ssh_key); |
| 18 | 18 | ||
| 19 | plan tests => 42; | 19 | plan tests => 33; |
| 20 | 20 | ||
| 21 | # Some random check strings/response | 21 | # Some random check strings/response |
| 22 | my @response = ('OK: Everything is fine', | 22 | my @response = ('OK: Everything is fine', |
| @@ -47,70 +47,70 @@ for (my $i=0; $i<4; $i++) { | |||
| 47 | "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[$i]; exit $i'" | 47 | "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[$i]; exit $i'" |
| 48 | ); | 48 | ); |
| 49 | cmp_ok($result->return_code, '==', $i, "Exit with return code $i"); | 49 | cmp_ok($result->return_code, '==', $i, "Exit with return code $i"); |
| 50 | is($result->output, $response[$i], "Status text is correct for check $i"); | 50 | like($result->output, "/$response[$i]/", "Status text is correct for check $i"); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | $result = NPTest->testCmd( | 53 | $result = NPTest->testCmd( |
| 54 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 0'" | 54 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 0'" |
| 55 | ); | 55 | ); |
| 56 | cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); | 56 | cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); |
| 57 | is($result->output, 'OK - check_by_ssh: Remote command \'exit 0\' returned status 0', "Status text if command returned none (OK)"); | 57 | like($result->output, '/command \'exit 0\' returned status 0/', "Status text if command returned none (OK)"); |
| 58 | 58 | ||
| 59 | $result = NPTest->testCmd( | 59 | $result = NPTest->testCmd( |
| 60 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 1'" | 60 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 1'" |
| 61 | ); | 61 | ); |
| 62 | cmp_ok($result->return_code, '==', 1, "Exit with return code 1 (WARNING)"); | 62 | cmp_ok($result->return_code, '==', 1, "Exit with return code 1 (WARNING)"); |
| 63 | is($result->output, 'WARNING - check_by_ssh: Remote command \'exit 1\' returned status 1', "Status text if command returned none (WARNING)"); | 63 | like($result->output, '/command \'exit 1\' returned status 1/', "Status text if command returned none (WARNING)"); |
| 64 | 64 | ||
| 65 | $result = NPTest->testCmd( | 65 | $result = NPTest->testCmd( |
| 66 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 2'" | 66 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 2'" |
| 67 | ); | 67 | ); |
| 68 | cmp_ok($result->return_code, '==', 2, "Exit with return code 2 (CRITICAL)"); | 68 | cmp_ok($result->return_code, '==', 2, "Exit with return code 2 (CRITICAL)"); |
| 69 | is($result->output, 'CRITICAL - check_by_ssh: Remote command \'exit 2\' returned status 2', "Status text if command returned none (CRITICAL)"); | 69 | like($result->output, '/command \'exit 2\' returned status 2/', "Status text if command returned none (CRITICAL)"); |
| 70 | 70 | ||
| 71 | $result = NPTest->testCmd( | 71 | $result = NPTest->testCmd( |
| 72 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 3'" | 72 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 3'" |
| 73 | ); | 73 | ); |
| 74 | cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)"); | 74 | cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)"); |
| 75 | is($result->output, 'UNKNOWN - check_by_ssh: Remote command \'exit 3\' returned status 3', "Status text if command returned none (UNKNOWN)"); | 75 | like($result->output, '/command \'exit 3\' returned status 3/', "Status text if command returned none (UNKNOWN)"); |
| 76 | 76 | ||
| 77 | $result = NPTest->testCmd( | 77 | $result = NPTest->testCmd( |
| 78 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 7'" | 78 | "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 7'" |
| 79 | ); | 79 | ); |
| 80 | cmp_ok($result->return_code, '==', 7, "Exit with return code 7 (out of bounds)"); | 80 | cmp_ok($result->return_code, '==', 3, "Exit with return code 3"); |
| 81 | is($result->output, 'UNKNOWN - check_by_ssh: Remote command \'exit 7\' returned status 7', "Status text if command returned none (out of bounds)"); | 81 | like($result->output, '/command \'exit 7\' returned status 7/', "Status text if command returned none (out of bounds)"); |
| 82 | 82 | ||
| 83 | $result = NPTest->testCmd( | 83 | $result = NPTest->testCmd( |
| 84 | "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[4]; exit 8'" | 84 | "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[4]; exit 8'" |
| 85 | ); | 85 | ); |
| 86 | cmp_ok($result->return_code, '==', 8, "Exit with return code 8 (out of bounds)"); | 86 | cmp_ok($result->return_code, '==', 3, "Exit with return code 3"); |
| 87 | is($result->output, $response[4], "Return proper status text even with unknown status codes"); | 87 | like($result->output, "/$response[4]/", "Return proper status text even with unknown status codes"); |
| 88 | 88 | ||
| 89 | $result = NPTest->testCmd( | 89 | $result = NPTest->testCmd( |
| 90 | "./check_by_ssh -i $ssh_key -H $ssh_service -F $ssh_conf -C 'exit 0'" | 90 | "./check_by_ssh -i $ssh_key -H $ssh_service -F $ssh_conf -C 'exit 0'" |
| 91 | ); | 91 | ); |
| 92 | cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); | 92 | cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); |
| 93 | is($result->output, 'OK - check_by_ssh: Remote command \'exit 0\' returned status 0', "Status text if command returned none (OK)"); | 93 | like($result->output, '/command \'exit 0\' returned status 0/', "Status text if command returned none (OK)"); |
| 94 | 94 | ||
| 95 | # Multiple active checks | 95 | # Multiple active checks |
| 96 | $result = NPTest->testCmd( | 96 | $result = NPTest->testCmd( |
| 97 | "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[1]; sh -c exit\\ 1' -C '$check[0]; sh -c exit\\ 0' -C '$check[3]; sh -c exit\\ 3' -C '$check[2]; sh -c exit\\ 2'" | 97 | "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[1]; sh -c exit\\ 1' -C '$check[0]; sh -c exit\\ 0' -C '$check[3]; sh -c exit\\ 3' -C '$check[2]; sh -c exit\\ 2'" |
| 98 | ); | 98 | ); |
| 99 | cmp_ok($result->return_code, '==', 0, "Multiple checks always return OK"); | 99 | cmp_ok($result->return_code, '==', 0, "Multiple checks always return OK"); |
| 100 | my @lines = split(/\n/, $result->output); | 100 | # my @lines = split(/\n/, $result->output); |
| 101 | cmp_ok(scalar(@lines), '==', 8, "Correct number of output lines for multiple checks"); | 101 | # cmp_ok(scalar(@lines), '==', 8, "Correct number of output lines for multiple checks"); |
| 102 | my %linemap = ( | 102 | # my %linemap = ( |
| 103 | '0' => '1', | 103 | # '0' => '1', |
| 104 | '2' => '0', | 104 | # '2' => '0', |
| 105 | '4' => '3', | 105 | # '4' => '3', |
| 106 | '6' => '2', | 106 | # '6' => '2', |
| 107 | ); | 107 | # ); |
| 108 | foreach my $line (0, 2, 4, 6) { | 108 | # foreach my $line (0, 2, 4, 6) { |
| 109 | my $code = $linemap{$line}; | 109 | # my $code = $linemap{$line}; |
| 110 | my $statline = $line+1; | 110 | # my $statline = $line+1; |
| 111 | is($lines[$line], "$response[$code]", "multiple checks status text is correct for line $line"); | 111 | # is($lines[$line], "$response[$code]", "multiple checks status text is correct for line $line"); |
| 112 | is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line"); | 112 | # is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line"); |
| 113 | } | 113 | # } |
| 114 | 114 | ||
| 115 | # Passive checks | 115 | # Passive checks |
| 116 | unlink("/tmp/check_by_ssh.$$"); | 116 | unlink("/tmp/check_by_ssh.$$"); |
diff --git a/plugins/t/check_dbi.t b/plugins/t/check_dbi.t index c24b5a8c..75444de4 100644 --- a/plugins/t/check_dbi.t +++ b/plugins/t/check_dbi.t | |||
| @@ -21,12 +21,12 @@ plan tests => $tests; | |||
| 21 | my $missing_driver_output = "failed to open DBI driver 'sqlite3'"; | 21 | my $missing_driver_output = "failed to open DBI driver 'sqlite3'"; |
| 22 | 22 | ||
| 23 | my $bad_driver_output = "/failed to open DBI driver 'nodriver'/"; | 23 | my $bad_driver_output = "/failed to open DBI driver 'nodriver'/"; |
| 24 | my $conn_time_output = "/OK - connection time: [0-9\.]+s \|/"; | 24 | my $conn_time_output = "/connection time: [0-9\.]+s \|/"; |
| 25 | my $missing_query_output = "/Must specify a query to execute/"; | 25 | my $missing_query_output = "/Must specify a query to execute/"; |
| 26 | my $no_rows_output = "/WARNING - no rows returned/"; | 26 | my $no_rows_output = "/no rows returned/"; |
| 27 | my $not_numeric_output = "/CRITICAL - result value is not a numeric:/"; | 27 | my $not_numeric_output = "/result value is not a numeric:/"; |
| 28 | my $query_time_output = "/OK - connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/"; | 28 | my $query_time_output = "/connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/"; |
| 29 | my $syntax_error_output = "/CRITICAL - failed to execute query 'GET ALL FROM test': 1: near \"GET\": syntax error/"; | 29 | my $syntax_error_output = "/1: near \"GET\": syntax error/"; |
| 30 | 30 | ||
| 31 | my $result; | 31 | my $result; |
| 32 | 32 | ||
diff --git a/plugins/t/check_ldap.t b/plugins/t/check_ldap.t index fcba0393..f3162ebb 100644 --- a/plugins/t/check_ldap.t +++ b/plugins/t/check_ldap.t | |||
| @@ -32,7 +32,7 @@ SKIP: { | |||
| 32 | 32 | ||
| 33 | $result = NPTest->testCmd("$command -H $hostname_invalid -b ou=blah -t 5"); | 33 | $result = NPTest->testCmd("$command -H $hostname_invalid -b ou=blah -t 5"); |
| 34 | is( $result->return_code, 2, "$command -H $hostname_invalid -b ou=blah -t 5" ); | 34 | is( $result->return_code, 2, "$command -H $hostname_invalid -b ou=blah -t 5" ); |
| 35 | is( $result->output, 'Could not bind to the LDAP server', "output ok" ); | 35 | like( $result->output, '/could not bind to the LDAP server/', "output ok" ); |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | SKIP: { | 38 | SKIP: { |
| @@ -42,30 +42,30 @@ SKIP: { | |||
| 42 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3"; | 42 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3"; |
| 43 | $result = NPTest->testCmd($cmd); | 43 | $result = NPTest->testCmd($cmd); |
| 44 | is( $result->return_code, 0, $cmd ); | 44 | is( $result->return_code, 0, $cmd ); |
| 45 | like( $result->output, '/^LDAP OK - \d+.\d+ seconds response time\|time=\d+\.\d+s;2\.0+;3\.0+;0\.0+$/', "output ok" ); | 45 | like( $result->output, '/connection time \d+.\d+s/', "output ok" ); |
| 46 | 46 | ||
| 47 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000 -C 10000001"; | 47 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000 -C 10000001"; |
| 48 | $result = NPTest->testCmd($cmd); | 48 | $result = NPTest->testCmd($cmd); |
| 49 | is( $result->return_code, 0, $cmd ); | 49 | is( $result->return_code, 0, $cmd ); |
| 50 | like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000;10000001;0\.0+$/', "output ok" ); | 50 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 51 | 51 | ||
| 52 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001:"; | 52 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001:"; |
| 53 | $result = NPTest->testCmd($cmd); | 53 | $result = NPTest->testCmd($cmd); |
| 54 | is( $result->return_code, 2, $cmd ); | 54 | is( $result->return_code, 2, $cmd ); |
| 55 | like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001:;0\.0+$/', "output ok" ); | 55 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 56 | 56 | ||
| 57 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 0 -C 0"; | 57 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 0 -C 0"; |
| 58 | $result = NPTest->testCmd($cmd); | 58 | $result = NPTest->testCmd($cmd); |
| 59 | is( $result->return_code, 2, $cmd ); | 59 | is( $result->return_code, 2, $cmd ); |
| 60 | like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;0;0;0\.0+$/', "output ok" ); | 60 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 61 | 61 | ||
| 62 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001"; | 62 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001"; |
| 63 | $result = NPTest->testCmd($cmd); | 63 | $result = NPTest->testCmd($cmd); |
| 64 | is( $result->return_code, 1, $cmd ); | 64 | is( $result->return_code, 1, $cmd ); |
| 65 | like( $result->output, '/^LDAP WARNING - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001;0\.0+$/', "output ok" ); | 65 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 66 | 66 | ||
| 67 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -C 10000001"; | 67 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -C 10000001"; |
| 68 | $result = NPTest->testCmd($cmd); | 68 | $result = NPTest->testCmd($cmd); |
| 69 | is( $result->return_code, 0, $cmd ); | 69 | is( $result->return_code, 0, $cmd ); |
| 70 | like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;;10000001;0\.0+$/', "output ok" ); | 70 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 71 | }; | 71 | }; |
diff --git a/plugins/t/check_mysql.t b/plugins/t/check_mysql.t index a383bc99..9114cccc 100644 --- a/plugins/t/check_mysql.t +++ b/plugins/t/check_mysql.t | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | # mysql -u$user -p$password -h$host $db | 11 | # mysql -u$user -p$password -h$host $db |
| 12 | 12 | ||
| 13 | use strict; | 13 | use strict; |
| 14 | use warnings; | ||
| 14 | use Test::More; | 15 | use Test::More; |
| 15 | use NPTest; | 16 | use NPTest; |
| 16 | 17 | ||
| @@ -40,7 +41,7 @@ SKIP: { | |||
| 40 | 41 | ||
| 41 | $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details"); | 42 | $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details"); |
| 42 | cmp_ok( $result->return_code, "==", 1, "No replicas defined" ); | 43 | cmp_ok( $result->return_code, "==", 1, "No replicas defined" ); |
| 43 | like( $result->output, "/No replicas defined/", "Correct error message"); | 44 | like( $result->output, "/no replicas defined/", "Correct error message"); |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | SKIP: { | 47 | SKIP: { |
| @@ -54,7 +55,7 @@ SKIP: { | |||
| 54 | 55 | ||
| 55 | $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details"); | 56 | $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details"); |
| 56 | cmp_ok( $result->return_code, "==", 1, "No replicas defined" ); | 57 | cmp_ok( $result->return_code, "==", 1, "No replicas defined" ); |
| 57 | like( $result->output, "/No replicas defined/", "Correct error message"); | 58 | like( $result->output, "/no replicas defined/", "Correct error message"); |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | SKIP: { | 61 | SKIP: { |
| @@ -70,5 +71,5 @@ SKIP: { | |||
| 70 | 71 | ||
| 71 | $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60:"); | 72 | $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60:"); |
| 72 | cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind'); | 73 | cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind'); |
| 73 | like( $result->output, "/^SLOW_REPLICA WARNING:/", "Output okay"); | 74 | like( $result->output, "/^slow_replica/", "Output okay"); |
| 74 | } | 75 | } |
diff --git a/plugins/t/check_mysql_query.t b/plugins/t/check_mysql_query.t index c30245b2..6de48bf6 100644 --- a/plugins/t/check_mysql_query.t +++ b/plugins/t/check_mysql_query.t | |||
| @@ -54,5 +54,5 @@ like( $result->output, "/No rows returned/", "No rows error message"); | |||
| 54 | 54 | ||
| 55 | $result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES' -H $mysqlserver $mysql_login_details"); | 55 | $result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES' -H $mysqlserver $mysql_login_details"); |
| 56 | cmp_ok( $result->return_code, '==', 2, "Data not numeric"); | 56 | cmp_ok( $result->return_code, '==', 2, "Data not numeric"); |
| 57 | like( $result->output, "/Is not a numeric/", "Data not numeric error message"); | 57 | like( $result->output, "/is not numeric/", "Data not numeric error message"); |
| 58 | 58 | ||
diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t index 73b4a1fd..c2f53c3d 100644 --- a/plugins/t/check_smtp.t +++ b/plugins/t/check_smtp.t | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | # | 5 | # |
| 6 | 6 | ||
| 7 | use strict; | 7 | use strict; |
| 8 | use warnings; | ||
| 8 | use Test::More; | 9 | use Test::More; |
| 9 | use NPTest; | 10 | use NPTest; |
| 10 | 11 | ||
| @@ -24,7 +25,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID", | |||
| 24 | "An invalid (not known to DNS) hostname", "nosuchhost" ); | 25 | "An invalid (not known to DNS) hostname", "nosuchhost" ); |
| 25 | my $res; | 26 | my $res; |
| 26 | 27 | ||
| 27 | plan tests => 15; | 28 | plan tests => 13; |
| 28 | 29 | ||
| 29 | SKIP: { | 30 | SKIP: { |
| 30 | skip "No SMTP server defined", 4 unless $host_tcp_smtp; | 31 | skip "No SMTP server defined", 4 unless $host_tcp_smtp; |
| @@ -42,12 +43,11 @@ SKIP: { | |||
| 42 | 43 | ||
| 43 | TODO: { | 44 | TODO: { |
| 44 | local $TODO = "Output is over two lines"; | 45 | local $TODO = "Output is over two lines"; |
| 45 | like ( $res->output, qr/^SMTP WARNING/, "Correct error message" ); | ||
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" ); | 48 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" ); |
| 49 | is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" ); | 49 | is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" ); |
| 50 | like ($res->output, qr/^CRITICAL - Cannot make SSL connection\./, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); | 50 | like ($res->output, qr/cannot create TLS context/, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | SKIP: { | 53 | SKIP: { |
| @@ -68,7 +68,6 @@ SKIP: { | |||
| 68 | skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls; | 68 | skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls; |
| 69 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" ); | 69 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" ); |
| 70 | is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" ); | 70 | is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" ); |
| 71 | like ($res->output, qr/^SMTP OK - /, "Check output of connecting to $host_tcp_smtp_tls with TLS" ); | ||
| 72 | 71 | ||
| 73 | my $unused_port = 4465; | 72 | my $unused_port = 4465; |
| 74 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); | 73 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); |
