2 * Copyright (c) 2013 Holger Weiss <holger@weiss.in-berlin.de>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
34 # include <inttypes.h>
46 #include <openssl/rand.h>
51 #include "send_nsca.h"
70 int exit_code
= EXIT_SUCCESS
;
72 static options
*get_options(int, char **);
73 static void free_options(options
*);
74 static int parse_backslash_escape(const char *);
75 static void delay_execution(unsigned int);
76 static unsigned long random_number(unsigned long);
77 static void forget_config(void);
78 static void usage(int) __attribute__((__noreturn__
));
81 main(int argc
, char **argv
)
88 log_set(LOG_LEVEL_WARNING
, LOG_TARGET_STDERR
);
90 if (atexit(log_close
) != 0 || atexit(forget_config
))
91 die("Cannot register function to be called on exit");
93 if (!ev_default_loop(0))
94 die("Cannot initialize libev");
96 opt
= get_options(argc
, argv
);
97 cfg
= conf_init(opt
->conf_file
!= NULL
?
98 opt
->conf_file
: DEFAULT_CONF_FILE
);
100 if (opt
->port
!= NULL
)
101 conf_setstr(cfg
, "port", opt
->port
);
102 if (opt
->server
!= NULL
)
103 conf_setstr(cfg
, "server", opt
->server
);
104 if (opt
->delay
!= -1)
105 conf_setint(cfg
, "delay", opt
->delay
);
106 if (opt
->timeout
!= -1)
107 conf_setint(cfg
, "timeout", opt
->timeout
);
109 log_set(opt
->log_level
, opt
->log_target
);
111 debug("%s starting up", nsca_version());
113 if (conf_getint(cfg
, "delay") != 0)
114 delay_execution((unsigned int)conf_getint(cfg
, "delay"));
116 (void)xasprintf(&host_port
, "%s:%s", conf_getstr(cfg
, "server"),
117 conf_getstr(cfg
, "port"));
119 (void)client_start(host_port
,
120 conf_getstr(cfg
, "tls_ciphers"),
121 conf_getint(cfg
, "timeout"),
122 opt
->raw_commands
? CLIENT_MODE_COMMAND
: CLIENT_MODE_CHECK_RESULT
,
126 (void)ev_run(EV_DEFAULT_UC_
0);
134 get_options(int argc
, char **argv
)
138 options
*opt
= xmalloc(sizeof(options
));
141 opt
->conf_file
= NULL
;
146 opt
->log_target
= -1;
148 opt
->delimiter
= '\t';
149 opt
->separator
= '\27';
150 opt
->raw_commands
= false;
153 if (strcmp(argv
[1], "--help") == 0)
155 if (strcmp(argv
[1], "--version") == 0) {
156 (void)puts(nsca_version());
161 while ((option
= getopt(argc
, argv
, "Cc:D:d:e:H:ho:p:SstVv")) != -1) {
166 opt
->raw_commands
= true;
169 if (opt
->conf_file
!= NULL
)
170 free(opt
->conf_file
);
171 opt
->conf_file
= xstrdup(optarg
);
174 opt
->delay
= atoi(optarg
);
176 die("-D argument must be a positive integer");
179 if ((character
= parse_backslash_escape(optarg
)) == EOF
)
180 die("-d argument must be a single character");
181 if (character
== '\27'
184 || character
== '\\')
185 die("Illegal delimiter specified with -d");
186 opt
->delimiter
= (char)character
;
189 if ((character
= parse_backslash_escape(optarg
)) == EOF
)
190 die("-e argument must be a single character");
191 opt
->separator
= (char)character
;
194 if (opt
->server
!= NULL
)
196 opt
->server
= xstrdup(optarg
);
201 opt
->timeout
= atoi(optarg
);
202 if (opt
->timeout
< 0)
203 die("-o argument must be a positive integer");
206 if (opt
->port
!= NULL
)
208 opt
->port
= xstrdup(optarg
);
211 opt
->log_target
= opt
->log_target
!= -1
212 ? LOG_TARGET_STDERR
| opt
->log_target
216 opt
->log_target
= opt
->log_target
!= -1
217 ? LOG_TARGET_SYSLOG
| opt
->log_target
221 notice("Ignoring -t option for backward compatibility");
224 (void)puts(nsca_version());
227 if (opt
->log_level
== -1)
228 opt
->log_level
= LOG_LEVEL_NOTICE
;
229 else if (opt
->log_level
< LOG_LEVEL_DEBUG
)
236 if (opt
->delimiter
== opt
->separator
)
237 die("Field delimiter must be different from record separator");
238 if (argc
- optind
> 0)
239 die("Unexpected non-option argument: %s", argv
[optind
]);
245 free_options(options
*opt
)
247 if (opt
->conf_file
!= NULL
)
248 free(opt
->conf_file
);
249 if (opt
->port
!= NULL
)
251 if (opt
->server
!= NULL
)
258 parse_backslash_escape(const char *sequence
)
260 char numeric
[6]; /* Space for "0x345". */
262 switch (strlen(sequence
)) {
264 return (unsigned char)sequence
[0];
266 if (sequence
[0] == '\\')
267 switch (sequence
[1]) {
282 case 'x': /* Fall through. */
286 return (unsigned char)sequence
[1];
288 /* Otherwise, fall through. */
289 case 3: /* Fall through. */
290 case 4: /* Fall through. */
293 * We support octal numbers with a leading zero and hexadecimal
294 * numbers prefixed with "0x" in addition to numeric backslash
297 if (sequence
[0] == '0' || sequence
[0] == '\\') {
301 (void)strcpy(numeric
, sequence
);
302 if (numeric
[0] == '\\') /* \x42 -> 0x42 */
304 value
= strtol(numeric
, &end
, 0);
305 if (*end
== '\0' && value
>= 0 && value
<= CHAR_MAX
)
306 return (unsigned char)value
;
307 /* Otherwise, fall through. */
309 /* Otherwise, fall through. */
316 delay_execution(unsigned int max_delay
)
319 struct timespec delay
;
321 delay
.tv_sec
= (time_t)random_number(max_delay
);
322 delay
.tv_nsec
= (long)random_number(1000000000U);
323 debug("Sleeping %ld seconds and %ld nanoseconds",
324 (long)delay
.tv_sec
, delay
.tv_nsec
);
325 (void)nanosleep(&delay
, NULL
);
327 unsigned int delay
= random_number(max_delay
+ 1);
329 debug("Sleeping %u seconds", delay
);
335 random_number(unsigned long range
)
337 unsigned long random_value
;
339 (void)RAND_pseudo_bytes((unsigned char *)&random_value
,
340 sizeof(random_value
));
342 /* See http://c-faq.com/lib/randrange.html for some caveats. */
343 return random_value
% range
;
350 char *password
= conf_getstr(cfg
, "password");
352 if (password
!= NULL
)
353 (void)memset(password
, 0, strlen(password
));
361 (void)fprintf(status
== EXIT_SUCCESS
? stdout
: stderr
,
362 "Usage: %s [<options>]\n\n"
364 " -C Accept `raw' monitoring commands.\n"
365 " -c <file> Use the specified configuration <file>.\n"
366 " -D <delay> Sleep up to <delay> seconds on startup.\n"
367 " -d <delimiter> Expect <delimiter> to separate input fields.\n"
368 " -e <separator> Expect <separator> to separate check results.\n"
369 " -H <server> Connect and talk to the specified <server>.\n"
370 " -h Print this usage information and exit.\n"
371 " -o <timeout> Use the specified connection <timeout>.\n"
372 " -p <port> Connect to the specified <port> on the server.\n"
373 " -S Write messages to the standard error output.\n"
374 " -s Write messages to syslog.\n"
375 " -t Ignore this option for backward compatibility.\n"
376 " -V Print version information and exit.\n"
377 " -v [-v [-v]] Increase the verbosity level.\n",
383 /* vim:set joinspaces noexpandtab textwidth=80 cinoptions=(4,u0: */