00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00029 #include "dnxPlugin.h"
00030
00031 #include "dnxError.h"
00032 #include "dnxDebug.h"
00033 #include "pfopen.h"
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <ctype.h>
00038 #include <string.h>
00039 #include <time.h>
00040 #include <errno.h>
00041 #include <unistd.h>
00042 #include <sys/types.h>
00043 #include <signal.h>
00044
00045 #define USE_POLL // use poll instead of select for descriptor multiplexing
00046
00047 #ifdef USE_POLL
00048 # include <poll.h>
00049 # define MPLEXER "poll"
00050 #else
00051 # include <sys/select.h>
00052 # define MPLEXER "select"
00053 #endif
00054
00055 #define elemcount(x) (sizeof(x)/sizeof(*(x)))
00056
00057 #define MAX_PLUGIN_PREFIX 1024
00058 #define MAX_PLUGIN_PATH 2048
00059 #define DNX_MAX_ARGV 256
00060 #define MAX_INPUT_BUFFER 1024
00061 #define DNX_MAX_PLUGIN_NAME 255
00062
00063
00064 typedef struct iDnxModule
00065 {
00066 char * path;
00067 void * handle;
00068 int (* init)(void);
00069 int (* deinit)(void);
00070 struct iDnxModule * next;
00071 struct iDnxModule * prev;
00072 } iDnxModule;
00073
00075 typedef struct iDnxPlugin
00076 {
00077 char * name;
00078 int (* func)(int argc, char ** argv);
00080 iDnxModule * parent;
00081 struct iDnxPlugin * next;
00082 struct iDnxPlugin * prev;
00083 } iDnxPlugin;
00084
00086 typedef struct { int unused; } DnxPlugin;
00087
00089 typedef struct { int unused; } DnxModule;
00090
00091 static iDnxModule * gModules;
00092 static iDnxPlugin * gPlugins;
00093 static char * gPluginPath;
00094 static int gInitialized = 0;
00095
00096
00097 #ifdef USE_NRPE_MODULE
00098 extern int mod_nrpe(int argc, char ** argv, char * resData);
00099 #endif
00100
00101
00102
00103
00104
00117 static char * dnxFgets(char * data, int size, FILE * fp, int timeout)
00118 {
00119 struct timeval tv;
00120 fd_set fd_read;
00121 int count, fdmax;
00122
00123 assert(data && size > 0 && fp && timeout > 0);
00124
00125 data[0] = 0;
00126
00127
00128 fdmax = fileno(fp);
00129
00130
00131 FD_ZERO(&fd_read);
00132 FD_SET(fdmax, &fd_read);
00133
00134
00135 tv.tv_sec = timeout;
00136 tv.tv_usec = 0L;
00137
00138
00139 if ((count = select(fdmax + 1, &fd_read, 0, 0, &tv)) < 0)
00140 return 0;
00141 else if (count == 0)
00142 return 0;
00143
00144 return fgets(data, size, fp);
00145 }
00146
00147
00148
00159 static void strip(char * buf)
00160 {
00161 register char * cp, * ep;
00162 assert(buf);
00163 ep = buf + strlen(buf);
00164 while (ep > buf && !isspace(ep[-1])) ep--;
00165 *ep = 0;
00166 cp = buf;
00167 while (isspace(*cp)) cp++;
00168 memmove(buf, cp, ep - cp);
00169 }
00170
00171
00172
00183 static int dnxPluginRegister(char * szPlugin, char * szErrMsg)
00184 {
00185 assert(gInitialized);
00186 return DNX_OK;
00187 }
00188
00189
00190
00199 static int dnxPluginLoad(DnxModule * module)
00200 {
00201 iDnxModule * imod = (iDnxModule *)module;
00202 assert(gInitialized);
00203 assert(module);
00204 return DNX_OK;
00205 }
00206
00207
00208
00215 static void dnxPluginUnload(DnxModule * module)
00216 {
00217 iDnxPlugin * imod = (iDnxPlugin *)module;
00218 assert(gInitialized);
00219 assert(module);
00220 }
00221
00222
00223
00232 static int dnxPluginBaseName(char * command, char * baseName, int maxData)
00233 {
00234 char * cp, * ep, * base;
00235 int len;
00236
00237
00238 for (cp = command; *cp && *cp <= ' '; cp++)
00239 ;
00240
00241 if (!*cp) return DNX_ERR_INVALID;
00242
00243
00244 for (ep=cp; *ep && *ep > ' '; ep++);
00245 if (ep == cp)
00246 return DNX_ERR_INVALID;
00247
00248
00249 for (base = (ep-1); base > cp && *base != '/'; base--);
00250 if (base == (ep-1))
00251 return DNX_ERR_INVALID;
00252 if (*base == '/')
00253 cp = base+1;
00254
00255
00256 if ((len = (ep - cp)) > maxData)
00257 return DNX_ERR_MEMORY;
00258
00259 memcpy(baseName, cp, len);
00260 baseName[len] = 0;
00261
00262 return DNX_OK;
00263 }
00264
00265
00266
00275 static int dnxPluginLocate(char * command, DnxPlugin ** plugin)
00276 {
00277 char baseName[DNX_MAX_PLUGIN_NAME + 1];
00278 int ret;
00279
00280 assert(gInitialized);
00281 assert(command && plugin);
00282
00283
00284 if ((ret = dnxPluginBaseName(command, baseName, DNX_MAX_PLUGIN_NAME)) != DNX_OK)
00285 return ret;
00286
00289
00290 #ifdef USE_NRPE_MODULE
00291 return (strcmp(baseName, "check_nrpe") ? DNX_ERR_NOTFOUND : DNX_OK);
00292 #else
00293 return DNX_ERR_NOTFOUND;
00294 #endif
00295 }
00296
00297
00298
00313 static int dnxPluginVector(char * command, int * argc, char ** argv, int maxargs)
00314 {
00315 char * cp, * ep;
00316 int idx = 0;
00317 int ret = DNX_OK;
00318
00319 assert(command && argc && argv && maxargs > 0);
00320
00321
00322 ep = command;
00323 while (idx < maxargs)
00324 {
00325
00326 for (cp=ep; *cp && *cp <= ' '; cp++);
00327 if (!*cp)
00328 break;
00329
00330
00331 for (ep=cp; *ep && *ep > ' '; ep++);
00332 if (ep == cp)
00333 break;
00334
00335
00336 if ((argv[idx] = (char *)xmalloc((ep-cp)+1)) == 0)
00337 {
00338 ret = DNX_ERR_MEMORY;
00339 break;
00340 }
00341 memcpy(argv[idx], cp, (ep-cp));
00342 argv[idx][ep-cp] = 0;
00343
00344 idx++;
00345 }
00346
00347
00348 argv[idx] = 0;
00349
00350 *argc = idx;
00351
00352 return ret;
00353 }
00354
00355
00356
00370 static void dnxPluginInternal(DnxPlugin * plugin, char * command, int * resCode,
00371 char * resData, int maxData, int timeout, char * myaddr)
00372 {
00373 char temp_buffer[MAX_INPUT_BUFFER + 1];
00374 char * argv[DNX_MAX_ARGV];
00375 int argc, len, ret;
00376
00377 assert(gInitialized);
00378
00381 assert(command && resCode && resData && maxData > 1 && timeout >= 0);
00382
00383
00384 *resData = 0;
00385
00386
00387 if ((ret = dnxPluginVector(command, &argc, argv, DNX_MAX_ARGV)) != DNX_OK)
00388 {
00389 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00390 resData += sprintf(resData, "(DNX: Vectorize command-line failed!)");
00391 if (myaddr)
00392 sprintf(resData, " (dnx node %s)", myaddr);
00393 return;
00394 }
00395
00398
00399 #ifdef USE_NRPE_MODULE
00400 *resCode = mod_nrpe(argc, argv, resData);
00401 #else
00402 {
00403 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00404 resData += sprintf(resData, "(DNX: Internal NRPE modules unavailable!)");
00405 if (myaddr)
00406 sprintf(resData, " (dnx node %s)", myaddr);
00407 }
00408 #endif
00409
00410
00411 if (!resData[0])
00412 {
00413
00414 resData += sprintf(resData, "(No output!)");
00415 if (myaddr)
00416 sprintf(resData, " (dnx node %s)", myaddr);
00417 }
00418
00419
00420 temp_buffer[0] = 0;
00421
00422
00423 if (*resCode < DNX_PLUGIN_RESULT_OK || *resCode > DNX_PLUGIN_RESULT_UNKNOWN)
00424 {
00425 len = strlen(temp_buffer);
00426 sprintf(temp_buffer+len, "[EC %d]", ((*resCode < 256) ? *resCode : (*resCode >> 8)));
00427 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00428 }
00429
00430
00431 if (temp_buffer[0])
00432 {
00433 strncat(temp_buffer, resData, MAX_INPUT_BUFFER);
00434 temp_buffer[MAX_INPUT_BUFFER] = 0;
00435 strncpy(resData, temp_buffer, maxData);
00436 resData[maxData-1] = 0;
00437 }
00438 }
00439
00440
00441
00455 static void dnxPluginExternal(char * command, int * resCode, char * resData,
00456 int maxData, int timeout, char * myaddr)
00457 {
00458 char temp_buffer[MAX_INPUT_BUFFER + 1];
00459 char temp_cmd[MAX_PLUGIN_PATH + 1];
00460 char * plugin, * cp, * bp, * ep;
00461 int p_out, p_err, count, len, isErrOutput = 0;
00462 time_t start_time;
00463 PFILE * pf;
00464 cp = 0;
00465
00466 #ifdef USE_POLL
00467 struct pollfd fds[2];
00468 #else
00469 int fdmax;
00470 struct timeval tv;
00471 fd_set fd_read;
00472 #endif
00473
00474 assert(gInitialized);
00475 assert(command && resCode && resData && maxData > 1);
00476
00477
00478 *resData = 0;
00479
00480
00481 for (cp = command; *cp && *cp <= ' '; cp++)
00482 ;
00483
00484 if (!*cp)
00485 {
00486 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00487 resData += sprintf(resData, "(DNX: Empty check command-line!)");
00488 if (myaddr)
00489 sprintf(resData, " (dnx node %s)", myaddr);
00490 return;
00491 }
00492
00493
00494 if (gPluginPath)
00495 {
00496
00497 for (bp = ep = cp; *ep && *ep > ' '; ep++)
00498 if (*ep == '/')
00499 bp = ep + 1;
00500
00501 if (bp == ep)
00502 {
00503 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00504 resData += sprintf(resData, "(DNX: Invalid check command-line!");
00505 if (myaddr)
00506 sprintf(resData, " (dnx node %s)", myaddr);
00507 return;
00508 }
00509
00510
00511 if ((len = strlen(gPluginPath) + strlen(bp)) > MAX_PLUGIN_PATH)
00512 {
00513 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00514 resData += sprintf(resData, "(DNX: Check command-line exceeds max size!)");
00515 if (myaddr)
00516 sprintf(resData, " (dnx node %s)", myaddr);
00517 return;
00518 }
00519
00520
00521 strcpy(temp_cmd, gPluginPath);
00522 strcat(temp_cmd, bp);
00523 plugin = temp_cmd;
00524 }
00525 else
00526 plugin = cp;
00527
00528
00529 if ((pf = pfopen(plugin, "r")) == 0)
00530 {
00531 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00532 resData += sprintf(resData, "(DNX: pfopen failed, %s!)", strerror(errno));
00533 if (myaddr)
00534 sprintf(resData, " (dnx node %s)", myaddr);
00535 return;
00536 }
00537
00538
00539 p_out = fileno(PF_OUT(pf));
00540 p_err = fileno(PF_ERR(pf));
00541
00542
00543 time(&start_time);
00544
00545 #ifdef USE_POLL
00546 fds[0].fd = p_out;
00547 fds[1].fd = p_err;
00548 fds[0].events = fds[1].events = POLLIN;
00549
00550 if ((count = poll(fds, elemcount(fds), timeout * 1000)) < 0)
00551 #else // !USE_POLL (instead use select)
00552
00553 fdmax = ((p_out > p_err) ? p_out : p_err) + 1;
00554
00555
00556 FD_ZERO(&fd_read);
00557 FD_SET(p_out, &fd_read);
00558 FD_SET(p_err, &fd_read);
00559
00560
00561 tv.tv_sec = timeout;
00562 tv.tv_usec = 0L;
00563
00564
00565
00566 if ((count = select(fdmax, &fd_read, 0, 0, &tv)) < 0)
00567 #endif // USE_POLL
00568 {
00569
00570 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00571 resData += sprintf(resData,
00572 "(DNX: " MPLEXER " failed on pipe, %s!)", strerror(errno));
00573 if (myaddr) sprintf(resData, " (dnx node %s)", myaddr);
00574
00575 pfkill(pf, SIGTERM);
00576 pfclose(pf);
00577
00578 return;
00579 }
00580
00581 if (count == 0)
00582 {
00583
00584 *resCode = DNX_PLUGIN_RESULT_CRITICAL;
00585 resData += sprintf(resData, "(DNX: Plugin Timed Out)");
00586 if (myaddr) sprintf(resData, " (dnx node %s)", myaddr);
00587
00588
00589 pfkill(pf, SIGTERM);
00590 sleep(1);
00591 pfkill(pf, SIGKILL);
00592 pfclose(pf);
00593
00594 return;
00595 }
00596
00597
00598 #ifdef USE_POLL
00599 if (fds[0].revents & POLLIN)
00600 #else
00601 if (FD_ISSET(p_out, &fd_read))
00602 #endif
00603 {
00604
00605 while (!resData[0] && fgets(resData, maxData, PF_OUT(pf)) != 0)
00606 strip(resData);
00607 while(fgets(temp_buffer, MAX_INPUT_BUFFER, PF_OUT(pf)));
00608 }
00609
00610 #ifdef USE_POLL
00611 if (!resData[0] && (fds[1].revents & POLLIN))
00612 #else
00613 if (!resData[0] && FD_ISSET(p_err, &fd_read))
00614 #endif
00615 {
00616
00617 while (!resData[0] && fgets(resData, maxData, PF_ERR(pf)) != 0)
00618 strip(resData);
00619 while(fgets(temp_buffer, MAX_INPUT_BUFFER, PF_ERR(pf)));
00620
00621 isErrOutput = 1;
00622 }
00623
00624
00625 if (!resData[0])
00626 {
00627 resData += sprintf(resData, "(No output!)");
00628 if (myaddr)
00629 sprintf(resData, " (dnx node %s)", myaddr);
00630 isErrOutput = 0;
00631 }
00632
00633
00634 *resCode = (pfclose(pf) >> 8);
00635
00636
00637 temp_buffer[0] = 0;
00638
00639
00640 if (isErrOutput)
00641 {
00642
00643 strcpy(temp_buffer, "[STDERR]");
00644 }
00645
00646
00647 if (*resCode < DNX_PLUGIN_RESULT_OK || *resCode > DNX_PLUGIN_RESULT_UNKNOWN)
00648 {
00649 len = strlen(temp_buffer);
00650 sprintf(temp_buffer+len, "[EC %d]", ((*resCode < 256) ? *resCode : (*resCode >> 8)));
00651 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00652 }
00653
00654
00655 if (temp_buffer[0])
00656 {
00657 strncat(temp_buffer, resData, MAX_INPUT_BUFFER);
00658 temp_buffer[MAX_INPUT_BUFFER] = 0;
00659 strncpy(resData, temp_buffer, maxData);
00660 resData[maxData - 1] = 0;
00661 }
00662 }
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861 void dnxPluginExecute(char * command, int * resCode, char * resData, int maxData, int timeout, char * myaddr)
00862 {
00863 DnxPlugin * plugin;
00864 int ret;
00865
00866 assert(gInitialized);
00867 assert(command && resCode && resData && maxData > 1);
00868
00869 dnxDebug(2, "dnxPluginExecute: Executing %s", command);
00870
00871
00872 if ((ret = dnxPluginLocate(command, &plugin)) == DNX_OK)
00873 {
00874 dnxPluginInternal(plugin, command, resCode, resData,maxData, timeout, myaddr);
00875 }else if (ret == DNX_ERR_NOTFOUND){
00876 dnxPluginExternal(command, resCode, resData,maxData, timeout, myaddr);
00877 }else{
00878 *resCode = DNX_PLUGIN_RESULT_UNKNOWN;
00879 resData += sprintf(resData, "(DNX: Unable to isolate check base name!)");
00880 if (myaddr)
00881 sprintf(resData, " (dnx node %s)", myaddr);
00882 }
00883 }
00884
00885
00886
00887 int dnxPluginInit(char * pluginPath)
00888 {
00889 int len, extra = 0;
00890
00891 assert(!gInitialized);
00892
00893
00894 gPluginPath = 0;
00895 gModules = 0;
00896 gPlugins = 0;
00897
00898 if (pluginPath)
00899 {
00900 if ((len = strlen(pluginPath)) < 1 || len > MAX_PLUGIN_PREFIX)
00901 {
00902 dnxLog("Invalid plugin path.");
00903 return DNX_ERR_INVALID;
00904 }
00905
00906
00907 if (*pluginPath != '/')
00908 {
00909 dnxLog("Plugin path is not absolute.");
00910 return DNX_ERR_INVALID;
00911 }
00912
00913
00914 extra = (pluginPath[len-1] == '/') ? 0 : 1;
00915 if ((gPluginPath = (char *)xmalloc(len + 1 + extra)) == 0)
00916 return DNX_ERR_MEMORY;
00917 strcpy(gPluginPath, pluginPath);
00918 if (extra)
00919 strcat(gPluginPath, "/");
00920 }
00921
00922 gInitialized = 1;
00923
00924 return DNX_OK;
00925 }
00926
00927
00928
00929 void dnxPluginRelease(void)
00930 {
00931 assert(gInitialized);
00932
00933 if (gPluginPath)
00934 {
00935 xfree(gPluginPath);
00936 gPluginPath = 0;
00937 }
00938
00941 gInitialized = 0;
00942 }
00943
00944
00945