From 19d76b3fb60aea7470b7bd03485669a531456d7a Mon Sep 17 00:00:00 2001 From: "M. Sean Finney" Date: Thu, 23 Mar 2006 22:58:38 +0000 Subject: [PATCH] - addition of include/exclude option for package names in check_apt, using POSIX regexp support. - various commenting and tidying of code/logic/output. - still haven't committed the Makefile.am/configure.in stuff. git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@1352 f882894a-f735-0410-b71e-b25c423dba1c --- plugins/check_apt.c | 148 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 31 deletions(-) diff --git a/plugins/check_apt.c b/plugins/check_apt.c index 867fe41..3fdee5d 100644 --- a/plugins/check_apt.c +++ b/plugins/check_apt.c @@ -30,23 +30,36 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; #include "common.h" #include "runcmd.h" #include "utils.h" +#include +/* for now define the various apt calls as constants. this may need + * to change later. */ #define APTGET_UPGRADE "/usr/bin/apt-get -o 'Debug::NoLocking=true' -s -qq upgrade" #define APTGET_DISTUPGRADE "/usr/bin/apt-get -o 'Debug::NoLocking=true' -s -qq dist-upgrade" #define APTGET_UPDATE "/usr/bin/apt-get -q update" +/* some standard functions */ int process_arguments(int, char **); void print_help(void); void print_usage(void); +/* run an apt-get update */ int run_update(void); +/* run an apt-get upgrade */ int run_upgrade(int *pkgcount); +/* add another clause to a regexp */ +char* add_to_regexp(char *expr, const char *next); + +/* configuration variables */ +static int verbose = 0; /* -v */ +static int do_update = 0; /* whether to call apt-get update */ +static int dist_upgrade = 0; /* whether to call apt-get dist-upgrade */ +static char* do_include = NULL; /* regexp to only include certain packages */ +static char* do_exclude = NULL; /* regexp to only exclude certain packages */ -static int verbose = 0; -static int do_update = 0; -static int dist_upgrade = 0; -static int stderr_warning = 0; -static int exec_warning = 0; +/* other global variables */ +static int stderr_warning = 0; /* if a cmd issued output on stderr */ +static int exec_warning = 0; /* if a cmd exited non-zero */ int main (int argc, char **argv) { int result=STATE_UNKNOWN, packages_available=0; @@ -68,24 +81,20 @@ int main (int argc, char **argv) { /* apt-get upgrade */ result = max_state(result, run_upgrade(&packages_available)); - if(stderr_warning){ - fprintf(stderr, "warning, output detected on stderr. "); - fprintf(stderr, "re-run with -v for more information.\n"); - } - if(packages_available > 0){ result = max_state(result, STATE_WARNING); } else { result = max_state(result, STATE_OK); } - printf("APT %s: %d packages available for %s.%s%s%s\n", + printf("APT %s: %d packages available for %s.%s%s%s%s\n", state_text(result), packages_available, (dist_upgrade)?"dist-upgrade":"upgrade", - (stderr_warning)?" (warnings detected)":"", + (stderr_warning)?" warnings detected":"", (stderr_warning && exec_warning)?",":"", - (exec_warning)?" (errors detected)":"" + (exec_warning)?" errors detected":"", + (stderr_warning||exec_warning)?". run with -v for information.":"" ); return result; @@ -102,19 +111,21 @@ int process_arguments (int argc, char **argv) { {"timeout", required_argument, 0, 't'}, {"update", no_argument, 0, 'u'}, {"dist-upgrade", no_argument, 0, 'd'}, + {"include", no_argument, 0, 'i'}, + {"exclude", no_argument, 0, 'e'}, {0, 0, 0, 0} }; while(1) { - c = getopt_long(argc, argv, "hVvt:ud", longopts, NULL); + c = getopt_long(argc, argv, "hVvt:udi:e:", longopts, NULL); if(c == -1 || c == EOF || c == 1) break; switch(c) { - case 'h': /* help */ + case 'h': print_help(); exit(STATE_OK); - case 'V': /* version */ + case 'V': print_revision(progname, revision); exit(STATE_OK); case 'v': @@ -129,6 +140,12 @@ int process_arguments (int argc, char **argv) { case 'u': do_update=1; break; + case 'i': + do_include=add_to_regexp(do_include, optarg); + break; + case 'e': + do_exclude=add_to_regexp(do_exclude, optarg); + break; default: /* print short usage statement if args not parsable */ usage_va(_("Unknown argument - %s"), optarg); @@ -153,7 +170,15 @@ found in Debian GNU/Linux\n\ printf(_(UT_TIMEOUT), timeout_interval); printf(_("\n\ -d, --dist-upgrade\n\ - Perform a dist-upgrade instead of normal upgrade.\n\n\ + Perform a dist-upgrade instead of normal upgrade.\n\ + -i, --include=REGEXP\n\ + Include only packages matching REGEXP. Can be specified multiple times;\n\ + the values will be combined together. Default is to include all packages.\n\ + -e, --exclude=REGEXP\n\ + Exclude packages matching REGEXP from the list of packages that would\n\ + otherwise be excluded. Can be specified multiple times; the values\n\ + will be combined together. Default is to exclude no packages.\n\n")); + printf(_("\ The following options require root privileges and should be used with care: \ \n\n")); printf(_("\ @@ -169,8 +194,37 @@ void print_usage(void){ /* run an apt-get upgrade */ int run_upgrade(int *pkgcount){ - int i=0, result=STATE_UNKNOWN, pc=0; + int i=0, result=STATE_UNKNOWN, regres=0, pc=0; struct output chld_out, chld_err; + regex_t ireg, ereg; + char rerrbuf[64]; + const char *default_include_expr="^Inst"; + + /* compile the regexps */ + if(do_include!=NULL){ + regres=regcomp(&ireg, do_include, REG_EXTENDED); + if(regres!=0) { + regerror(regres, &ireg, rerrbuf, 64); + die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", + progname, rerrbuf); + } + } else { + regres=regcomp(&ireg, default_include_expr, REG_EXTENDED); + if(regres!=0) { + regerror(regres, &ireg, rerrbuf, 64); + die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", + progname, rerrbuf); + } + } + if(do_exclude!=NULL){ + regres=regcomp(&ereg, do_exclude, REG_EXTENDED); + if(regres!=0) { + regerror(regres, &ereg, rerrbuf, 64); + die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", + progname, rerrbuf); + } + } + /* run the upgrade */ if(dist_upgrade==0){ @@ -178,13 +232,14 @@ int run_upgrade(int *pkgcount){ } else { result = np_runcmd(APTGET_DISTUPGRADE, &chld_out, &chld_err, 0); } - /* apt-get only changes exit status if there is an internal error */ + /* apt-get upgrade only changes exit status if there is an + * internal error when run in dry-run mode. therefore we will + * treat such an error as UNKNOWN */ if(result != 0){ exec_warning=1; result = STATE_UNKNOWN; - fprintf(stderr, "'%s' exited with non-zero status.\n%s\n", - APTGET_UPGRADE, - "Run again with -v for more info."); + fprintf(stderr, "'%s' exited with non-zero status.\n", + APTGET_UPGRADE); } /* parse the output, which should only consist of lines like @@ -192,14 +247,25 @@ int run_upgrade(int *pkgcount){ * Inst package .... * Conf package .... * - * so we'll filter based on "Inst". If we ever want to do + * so we'll filter based on "Inst" for the time being. later + * we may need to switch to the --print-uris output format, + * in which case the logic here will slightly change. */ for(i = 0; i < chld_out.lines; i++) { - if(strncmp(chld_out.line[i], "Inst", 4)==0){ - if(verbose){ - printf("%s\n", chld_out.line[i]); + if(verbose){ + printf("%s\n", chld_out.line[i]); + } + /* if it is a package we care about */ + if(regexec(&ireg, chld_out.line[i], 0, NULL, 0)==0){ + /* if we're not excluding, or it's not in the + * list of stuff to exclude */ + if(do_exclude==NULL || + regexec(&ereg, chld_out.line[i], 0, NULL, 0)!=0){ + pc++; + if(verbose){ + printf("*%s\n", chld_out.line[i]); + } } - pc++; } } *pkgcount=pc; @@ -210,7 +276,7 @@ int run_upgrade(int *pkgcount){ result = max_state(result, STATE_WARNING); if(verbose){ for(i = 0; i < chld_err.lines; i++) { - printf("%s\n", chld_err.line[i]); + fprintf(stderr, "%s\n", chld_err.line[i]); } } } @@ -224,10 +290,12 @@ int run_update(void){ /* run the upgrade */ result = np_runcmd(APTGET_UPDATE, &chld_out, &chld_err, 0); - /* apt-get only changes exit status if there is an internal error */ + /* apt-get update changes exit status if it can't fetch packages. + * since we were explicitly asked to do so, this is treated as + * a critical error. */ if(result != 0){ exec_warning=1; - result = STATE_UNKNOWN; + result = STATE_CRITICAL; fprintf(stderr, "'%s' exited with non-zero status.\n", APTGET_UPDATE); } @@ -244,9 +312,27 @@ int run_update(void){ result = max_state(result, STATE_WARNING); if(verbose){ for(i = 0; i < chld_err.lines; i++) { - printf("%s\n", chld_err.line[i]); + fprintf(stderr, "%s\n", chld_err.line[i]); } } } return result; } + +char* add_to_regexp(char *expr, const char *next){ + char *re=NULL; + + if(expr==NULL){ + re=malloc(sizeof(char)*(strlen("^Inst () ")+strlen(next)+1)); + if(!re) die(STATE_UNKNOWN, "malloc failed!\n"); + sprintf(re, "^Inst (%s) ", next); + } else { + /* resize it, adding an extra char for the new '|' separator */ + re=realloc(expr, sizeof(char)*strlen(expr)+1+strlen(next)+1); + if(!re) die(STATE_UNKNOWN, "realloc failed!\n"); + /* append it starting at ')' in the old re */ + sprintf((char*)(re+strlen(re)-2), "|%s) ", next); + } + + return re; +} -- 2.30.2