diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/check_apt.c | 148 |
1 files changed, 117 insertions, 31 deletions
diff --git a/plugins/check_apt.c b/plugins/check_apt.c index 867fe41e..3fdee5d3 100644 --- a/plugins/check_apt.c +++ b/plugins/check_apt.c | |||
@@ -30,23 +30,36 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; | |||
30 | #include "common.h" | 30 | #include "common.h" |
31 | #include "runcmd.h" | 31 | #include "runcmd.h" |
32 | #include "utils.h" | 32 | #include "utils.h" |
33 | #include <regex.h> | ||
33 | 34 | ||
35 | /* for now define the various apt calls as constants. this may need | ||
36 | * to change later. */ | ||
34 | #define APTGET_UPGRADE "/usr/bin/apt-get -o 'Debug::NoLocking=true' -s -qq upgrade" | 37 | #define APTGET_UPGRADE "/usr/bin/apt-get -o 'Debug::NoLocking=true' -s -qq upgrade" |
35 | #define APTGET_DISTUPGRADE "/usr/bin/apt-get -o 'Debug::NoLocking=true' -s -qq dist-upgrade" | 38 | #define APTGET_DISTUPGRADE "/usr/bin/apt-get -o 'Debug::NoLocking=true' -s -qq dist-upgrade" |
36 | #define APTGET_UPDATE "/usr/bin/apt-get -q update" | 39 | #define APTGET_UPDATE "/usr/bin/apt-get -q update" |
37 | 40 | ||
41 | /* some standard functions */ | ||
38 | int process_arguments(int, char **); | 42 | int process_arguments(int, char **); |
39 | void print_help(void); | 43 | void print_help(void); |
40 | void print_usage(void); | 44 | void print_usage(void); |
41 | 45 | ||
46 | /* run an apt-get update */ | ||
42 | int run_update(void); | 47 | int run_update(void); |
48 | /* run an apt-get upgrade */ | ||
43 | int run_upgrade(int *pkgcount); | 49 | int run_upgrade(int *pkgcount); |
50 | /* add another clause to a regexp */ | ||
51 | char* add_to_regexp(char *expr, const char *next); | ||
52 | |||
53 | /* configuration variables */ | ||
54 | static int verbose = 0; /* -v */ | ||
55 | static int do_update = 0; /* whether to call apt-get update */ | ||
56 | static int dist_upgrade = 0; /* whether to call apt-get dist-upgrade */ | ||
57 | static char* do_include = NULL; /* regexp to only include certain packages */ | ||
58 | static char* do_exclude = NULL; /* regexp to only exclude certain packages */ | ||
44 | 59 | ||
45 | static int verbose = 0; | 60 | /* other global variables */ |
46 | static int do_update = 0; | 61 | static int stderr_warning = 0; /* if a cmd issued output on stderr */ |
47 | static int dist_upgrade = 0; | 62 | static int exec_warning = 0; /* if a cmd exited non-zero */ |
48 | static int stderr_warning = 0; | ||
49 | static int exec_warning = 0; | ||
50 | 63 | ||
51 | int main (int argc, char **argv) { | 64 | int main (int argc, char **argv) { |
52 | int result=STATE_UNKNOWN, packages_available=0; | 65 | int result=STATE_UNKNOWN, packages_available=0; |
@@ -68,24 +81,20 @@ int main (int argc, char **argv) { | |||
68 | /* apt-get upgrade */ | 81 | /* apt-get upgrade */ |
69 | result = max_state(result, run_upgrade(&packages_available)); | 82 | result = max_state(result, run_upgrade(&packages_available)); |
70 | 83 | ||
71 | if(stderr_warning){ | ||
72 | fprintf(stderr, "warning, output detected on stderr. "); | ||
73 | fprintf(stderr, "re-run with -v for more information.\n"); | ||
74 | } | ||
75 | |||
76 | if(packages_available > 0){ | 84 | if(packages_available > 0){ |
77 | result = max_state(result, STATE_WARNING); | 85 | result = max_state(result, STATE_WARNING); |
78 | } else { | 86 | } else { |
79 | result = max_state(result, STATE_OK); | 87 | result = max_state(result, STATE_OK); |
80 | } | 88 | } |
81 | 89 | ||
82 | printf("APT %s: %d packages available for %s.%s%s%s\n", | 90 | printf("APT %s: %d packages available for %s.%s%s%s%s\n", |
83 | state_text(result), | 91 | state_text(result), |
84 | packages_available, | 92 | packages_available, |
85 | (dist_upgrade)?"dist-upgrade":"upgrade", | 93 | (dist_upgrade)?"dist-upgrade":"upgrade", |
86 | (stderr_warning)?" (warnings detected)":"", | 94 | (stderr_warning)?" warnings detected":"", |
87 | (stderr_warning && exec_warning)?",":"", | 95 | (stderr_warning && exec_warning)?",":"", |
88 | (exec_warning)?" (errors detected)":"" | 96 | (exec_warning)?" errors detected":"", |
97 | (stderr_warning||exec_warning)?". run with -v for information.":"" | ||
89 | ); | 98 | ); |
90 | 99 | ||
91 | return result; | 100 | return result; |
@@ -102,19 +111,21 @@ int process_arguments (int argc, char **argv) { | |||
102 | {"timeout", required_argument, 0, 't'}, | 111 | {"timeout", required_argument, 0, 't'}, |
103 | {"update", no_argument, 0, 'u'}, | 112 | {"update", no_argument, 0, 'u'}, |
104 | {"dist-upgrade", no_argument, 0, 'd'}, | 113 | {"dist-upgrade", no_argument, 0, 'd'}, |
114 | {"include", no_argument, 0, 'i'}, | ||
115 | {"exclude", no_argument, 0, 'e'}, | ||
105 | {0, 0, 0, 0} | 116 | {0, 0, 0, 0} |
106 | }; | 117 | }; |
107 | 118 | ||
108 | while(1) { | 119 | while(1) { |
109 | c = getopt_long(argc, argv, "hVvt:ud", longopts, NULL); | 120 | c = getopt_long(argc, argv, "hVvt:udi:e:", longopts, NULL); |
110 | 121 | ||
111 | if(c == -1 || c == EOF || c == 1) break; | 122 | if(c == -1 || c == EOF || c == 1) break; |
112 | 123 | ||
113 | switch(c) { | 124 | switch(c) { |
114 | case 'h': /* help */ | 125 | case 'h': |
115 | print_help(); | 126 | print_help(); |
116 | exit(STATE_OK); | 127 | exit(STATE_OK); |
117 | case 'V': /* version */ | 128 | case 'V': |
118 | print_revision(progname, revision); | 129 | print_revision(progname, revision); |
119 | exit(STATE_OK); | 130 | exit(STATE_OK); |
120 | case 'v': | 131 | case 'v': |
@@ -129,6 +140,12 @@ int process_arguments (int argc, char **argv) { | |||
129 | case 'u': | 140 | case 'u': |
130 | do_update=1; | 141 | do_update=1; |
131 | break; | 142 | break; |
143 | case 'i': | ||
144 | do_include=add_to_regexp(do_include, optarg); | ||
145 | break; | ||
146 | case 'e': | ||
147 | do_exclude=add_to_regexp(do_exclude, optarg); | ||
148 | break; | ||
132 | default: | 149 | default: |
133 | /* print short usage statement if args not parsable */ | 150 | /* print short usage statement if args not parsable */ |
134 | usage_va(_("Unknown argument - %s"), optarg); | 151 | usage_va(_("Unknown argument - %s"), optarg); |
@@ -153,7 +170,15 @@ found in Debian GNU/Linux\n\ | |||
153 | printf(_(UT_TIMEOUT), timeout_interval); | 170 | printf(_(UT_TIMEOUT), timeout_interval); |
154 | printf(_("\n\ | 171 | printf(_("\n\ |
155 | -d, --dist-upgrade\n\ | 172 | -d, --dist-upgrade\n\ |
156 | Perform a dist-upgrade instead of normal upgrade.\n\n\ | 173 | Perform a dist-upgrade instead of normal upgrade.\n\ |
174 | -i, --include=REGEXP\n\ | ||
175 | Include only packages matching REGEXP. Can be specified multiple times;\n\ | ||
176 | the values will be combined together. Default is to include all packages.\n\ | ||
177 | -e, --exclude=REGEXP\n\ | ||
178 | Exclude packages matching REGEXP from the list of packages that would\n\ | ||
179 | otherwise be excluded. Can be specified multiple times; the values\n\ | ||
180 | will be combined together. Default is to exclude no packages.\n\n")); | ||
181 | printf(_("\ | ||
157 | The following options require root privileges and should be used with care: \ | 182 | The following options require root privileges and should be used with care: \ |
158 | \n\n")); | 183 | \n\n")); |
159 | printf(_("\ | 184 | printf(_("\ |
@@ -169,8 +194,37 @@ void print_usage(void){ | |||
169 | 194 | ||
170 | /* run an apt-get upgrade */ | 195 | /* run an apt-get upgrade */ |
171 | int run_upgrade(int *pkgcount){ | 196 | int run_upgrade(int *pkgcount){ |
172 | int i=0, result=STATE_UNKNOWN, pc=0; | 197 | int i=0, result=STATE_UNKNOWN, regres=0, pc=0; |
173 | struct output chld_out, chld_err; | 198 | struct output chld_out, chld_err; |
199 | regex_t ireg, ereg; | ||
200 | char rerrbuf[64]; | ||
201 | const char *default_include_expr="^Inst"; | ||
202 | |||
203 | /* compile the regexps */ | ||
204 | if(do_include!=NULL){ | ||
205 | regres=regcomp(&ireg, do_include, REG_EXTENDED); | ||
206 | if(regres!=0) { | ||
207 | regerror(regres, &ireg, rerrbuf, 64); | ||
208 | die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", | ||
209 | progname, rerrbuf); | ||
210 | } | ||
211 | } else { | ||
212 | regres=regcomp(&ireg, default_include_expr, REG_EXTENDED); | ||
213 | if(regres!=0) { | ||
214 | regerror(regres, &ireg, rerrbuf, 64); | ||
215 | die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", | ||
216 | progname, rerrbuf); | ||
217 | } | ||
218 | } | ||
219 | if(do_exclude!=NULL){ | ||
220 | regres=regcomp(&ereg, do_exclude, REG_EXTENDED); | ||
221 | if(regres!=0) { | ||
222 | regerror(regres, &ereg, rerrbuf, 64); | ||
223 | die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", | ||
224 | progname, rerrbuf); | ||
225 | } | ||
226 | } | ||
227 | |||
174 | 228 | ||
175 | /* run the upgrade */ | 229 | /* run the upgrade */ |
176 | if(dist_upgrade==0){ | 230 | if(dist_upgrade==0){ |
@@ -178,13 +232,14 @@ int run_upgrade(int *pkgcount){ | |||
178 | } else { | 232 | } else { |
179 | result = np_runcmd(APTGET_DISTUPGRADE, &chld_out, &chld_err, 0); | 233 | result = np_runcmd(APTGET_DISTUPGRADE, &chld_out, &chld_err, 0); |
180 | } | 234 | } |
181 | /* apt-get only changes exit status if there is an internal error */ | 235 | /* apt-get upgrade only changes exit status if there is an |
236 | * internal error when run in dry-run mode. therefore we will | ||
237 | * treat such an error as UNKNOWN */ | ||
182 | if(result != 0){ | 238 | if(result != 0){ |
183 | exec_warning=1; | 239 | exec_warning=1; |
184 | result = STATE_UNKNOWN; | 240 | result = STATE_UNKNOWN; |
185 | fprintf(stderr, "'%s' exited with non-zero status.\n%s\n", | 241 | fprintf(stderr, "'%s' exited with non-zero status.\n", |
186 | APTGET_UPGRADE, | 242 | APTGET_UPGRADE); |
187 | "Run again with -v for more info."); | ||
188 | } | 243 | } |
189 | 244 | ||
190 | /* parse the output, which should only consist of lines like | 245 | /* parse the output, which should only consist of lines like |
@@ -192,14 +247,25 @@ int run_upgrade(int *pkgcount){ | |||
192 | * Inst package .... | 247 | * Inst package .... |
193 | * Conf package .... | 248 | * Conf package .... |
194 | * | 249 | * |
195 | * so we'll filter based on "Inst". If we ever want to do | 250 | * so we'll filter based on "Inst" for the time being. later |
251 | * we may need to switch to the --print-uris output format, | ||
252 | * in which case the logic here will slightly change. | ||
196 | */ | 253 | */ |
197 | for(i = 0; i < chld_out.lines; i++) { | 254 | for(i = 0; i < chld_out.lines; i++) { |
198 | if(strncmp(chld_out.line[i], "Inst", 4)==0){ | 255 | if(verbose){ |
199 | if(verbose){ | 256 | printf("%s\n", chld_out.line[i]); |
200 | printf("%s\n", chld_out.line[i]); | 257 | } |
258 | /* if it is a package we care about */ | ||
259 | if(regexec(&ireg, chld_out.line[i], 0, NULL, 0)==0){ | ||
260 | /* if we're not excluding, or it's not in the | ||
261 | * list of stuff to exclude */ | ||
262 | if(do_exclude==NULL || | ||
263 | regexec(&ereg, chld_out.line[i], 0, NULL, 0)!=0){ | ||
264 | pc++; | ||
265 | if(verbose){ | ||
266 | printf("*%s\n", chld_out.line[i]); | ||
267 | } | ||
201 | } | 268 | } |
202 | pc++; | ||
203 | } | 269 | } |
204 | } | 270 | } |
205 | *pkgcount=pc; | 271 | *pkgcount=pc; |
@@ -210,7 +276,7 @@ int run_upgrade(int *pkgcount){ | |||
210 | result = max_state(result, STATE_WARNING); | 276 | result = max_state(result, STATE_WARNING); |
211 | if(verbose){ | 277 | if(verbose){ |
212 | for(i = 0; i < chld_err.lines; i++) { | 278 | for(i = 0; i < chld_err.lines; i++) { |
213 | printf("%s\n", chld_err.line[i]); | 279 | fprintf(stderr, "%s\n", chld_err.line[i]); |
214 | } | 280 | } |
215 | } | 281 | } |
216 | } | 282 | } |
@@ -224,10 +290,12 @@ int run_update(void){ | |||
224 | 290 | ||
225 | /* run the upgrade */ | 291 | /* run the upgrade */ |
226 | result = np_runcmd(APTGET_UPDATE, &chld_out, &chld_err, 0); | 292 | result = np_runcmd(APTGET_UPDATE, &chld_out, &chld_err, 0); |
227 | /* apt-get only changes exit status if there is an internal error */ | 293 | /* apt-get update changes exit status if it can't fetch packages. |
294 | * since we were explicitly asked to do so, this is treated as | ||
295 | * a critical error. */ | ||
228 | if(result != 0){ | 296 | if(result != 0){ |
229 | exec_warning=1; | 297 | exec_warning=1; |
230 | result = STATE_UNKNOWN; | 298 | result = STATE_CRITICAL; |
231 | fprintf(stderr, "'%s' exited with non-zero status.\n", | 299 | fprintf(stderr, "'%s' exited with non-zero status.\n", |
232 | APTGET_UPDATE); | 300 | APTGET_UPDATE); |
233 | } | 301 | } |
@@ -244,9 +312,27 @@ int run_update(void){ | |||
244 | result = max_state(result, STATE_WARNING); | 312 | result = max_state(result, STATE_WARNING); |
245 | if(verbose){ | 313 | if(verbose){ |
246 | for(i = 0; i < chld_err.lines; i++) { | 314 | for(i = 0; i < chld_err.lines; i++) { |
247 | printf("%s\n", chld_err.line[i]); | 315 | fprintf(stderr, "%s\n", chld_err.line[i]); |
248 | } | 316 | } |
249 | } | 317 | } |
250 | } | 318 | } |
251 | return result; | 319 | return result; |
252 | } | 320 | } |
321 | |||
322 | char* add_to_regexp(char *expr, const char *next){ | ||
323 | char *re=NULL; | ||
324 | |||
325 | if(expr==NULL){ | ||
326 | re=malloc(sizeof(char)*(strlen("^Inst () ")+strlen(next)+1)); | ||
327 | if(!re) die(STATE_UNKNOWN, "malloc failed!\n"); | ||
328 | sprintf(re, "^Inst (%s) ", next); | ||
329 | } else { | ||
330 | /* resize it, adding an extra char for the new '|' separator */ | ||
331 | re=realloc(expr, sizeof(char)*strlen(expr)+1+strlen(next)+1); | ||
332 | if(!re) die(STATE_UNKNOWN, "realloc failed!\n"); | ||
333 | /* append it starting at ')' in the old re */ | ||
334 | sprintf((char*)(re+strlen(re)-2), "|%s) ", next); | ||
335 | } | ||
336 | |||
337 | return re; | ||
338 | } | ||