Have you ever attempted to write a function in C to execute a command and parse the output? I think I’d rather just let the Nagios library do the heavy lifting for me.
This blog post is going to cover the basics of compiling libnagios, and linking the Nagios library to your application. I’ll be focusing on using some of the built-in Nagios functionality, specifically the runcmd_open() function.
I’m going to assume you have a sane build environment set up (where tools like make and ./configure are working) before we go any further. If you are following along, now would be the time to get these in order.
First, download the source code and extract it. You can get a copy of the Nagios Core source at https://github.com/NagiosEnterprises/nagioscore/archive/master.zip. Once you’ve downloaded it and extracted the files, open up nagioscore-master/lib/runcmd.h (https://github.com/NagiosEnterprises/nagioscore/blob/master/lib/runcmd.h). Search for “extern int runcmd_open”, as of the time of this writing, that should bring you to line 77, where our function is declared:
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * Start a command from a command string * @param[in] cmd The command to launch * @param[out] pfd Child's stdout filedescriptor * @param[out] pfderr Child's stderr filedescriptor * @param[in] env Currently ignored for portability * @param[in] iobreg The callback function to register the iobrokers for the read ends of the pipe * @param[in] iobregarg The "arg" value to pass to iobroker_register() */ extern int runcmd_open(const char *cmd, int *pfd, int *pfderr, char **env, void (*iobreg)(int, int, void *), void *iobregarg) __attribute__((__nonnull__(1, 2, 3, 5, 6))); |
So what does all that mean? It means we need a command to execute, a file descriptor for stdout, another filedescriptor for stderr. Our application doesn’t need a callback function to register iobrokers or a value to pass. But, since these are declared non null, we’ll have to get creative.
Let’s create a file, named test.c in the root of the nagioscore-master directory. First, we need to include our libnagios header.
1 |
#include "lib/libnagios.h" |
Then we define our fake iobroker_register function. This is essentially just a placeholder, as we aren’t (yet) particularly interested in assigning a function to execute when our stdout/stderr stops reading.
3 4 |
/* define a fake iobroker_register function for the libnagios call */ static void fake_iobreg(int fdout, int fderr, void *arg) { } |
Next, we set up our variables that we’ll be using to pass to the runcmd_open() function. We don’t need an env variable, since that argument can accept a NULL value, we’re just going to pass that in (especially since it is unused anyway).
6 7 8 9 10 11 12 13 14 15 16 17 18 |
int main(void) { /* set up the vars */ int BUFFER = 128; char *cmd; int pfd[2] = {-1, -1}; int pfderr[2] = {-1, -1}; int fake_iobregarg = 0; int fd; char *out = calloc(1, BUFFER); /* lets keep this simple for now */ asprintf(&cmd, "echo hello"); |
Now we execute runcmd_open(), and let the Nagios library do its magic! This will put stdout in pfd[0] and stderr in pfderr[0].
20 21 |
/* run the command */ fd = runcmd_open(cmd, pfd, pfderr, NULL, fake_iobreg, &fake_iobregarg); |
Let’s copy the stdout to our out var and print some information relating to the command we executed and that command’s output.
23 24 25 26 27 28 |
/* get the output from the stdout file descriptor into the out var */ read(pfd[0], out, BUFFER); /* output our information */ printf("The command we're executing is: %s\n", cmd); printf("The output of the command is: %s\n", out); |
Finally, we clean up our memory and exit the program.
30 31 32 33 34 35 36 37 38 |
/* house-keeping */ free(cmd); free(out); close(pfd[0]); close(pfderr[0]); close(fd); return 0; } |
Here’s the file in its entirety:
test.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include "../lib/libnagios.h" /* define a fake iobroker_register function for the libnagios call */ static void fake_iobreg(int fdout, int fderr, void *arg) { } int main(void) { /* set up the vars */ int BUFFER = 128; char *cmd; int pfd[2] = {-1, -1}; int pfderr[2] = {-1, -1}; int fake_iobregarg = 0; int fd; char *out = calloc(1, BUFFER); /* lets keep this simple for now */ asprintf(&cmd, "echo hello"); /* run the command */ fd = runcmd_open(cmd, pfd, pfderr, NULL, fake_iobreg, &fake_iobregarg); /* get the output from the stdout file descriptor into the out var */ read(pfd[0], out, BUFFER); /* output our information */ printf("The command we're executing is: %s\n", cmd); printf("The output of the command is: %s\n", out); /* house-keeping */ free(cmd); free(out); close(pfd[0]); close(pfderr[0]); close(fd); return 0; } |
Let’s see it in action! First we’re going to compile our Nagios library! Open up your terminal and let’s get to library compilin’:
1 2 3 4 |
cd /path/to/nagioscore-master ./configure make lib/libnagios.a make install-lib |
Those commands should have compiled your Nagios library and then placed it in /usr/local/nagios/lib. Now, we’re finally ready to compile our program:
1 |
gcc -L/usr/local/nagios/lib test.c -lnagios -o test |
Now, if everything went well up this point, you should be able to execute our basic program with the following command:
1 |
./test |
Your output should be similar to the following:
1 2 3 4 5 |
# ./test The command we're executing is: echo hello The output of the command is: hello # |
I hope that you’ve learned a few things about using the Nagios library in your own code. Questions, comments, and suggestions for future posts are all welcome below in the comments section.
– Bryan Heden
0 Responses to “Extending Nagios functionality with libnagios”