diff options
-rw-r--r-- | plugins/check_apt.c | 195 |
1 files changed, 144 insertions, 51 deletions
diff --git a/plugins/check_apt.c b/plugins/check_apt.c index db328a0..445659d 100644 --- a/plugins/check_apt.c +++ b/plugins/check_apt.c | |||
@@ -32,12 +32,18 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; | |||
32 | #include "utils.h" | 32 | #include "utils.h" |
33 | #include <regex.h> | 33 | #include <regex.h> |
34 | 34 | ||
35 | /* for now define the various apt calls as constants. this may need | 35 | /* some constants */ |
36 | * to change later. */ | 36 | typedef enum { UPGRADE, DIST_UPGRADE, NO_UPGRADE } upgrade_type; |
37 | #define APTGET_UPGRADE "/usr/bin/apt-get -o 'Debug::NoLocking=true' -s -qq upgrade" | 37 | |
38 | #define APTGET_DISTUPGRADE "/usr/bin/apt-get -o 'Debug::NoLocking=true' -s -qq dist-upgrade" | 38 | /* the default opts can be overridden via the cmdline */ |
39 | #define APTGET_UPDATE "/usr/bin/apt-get -q update" | 39 | #define UPGRADE_DEFAULT_OPTS "-o 'Debug::NoLocking=true' -s -qq" |
40 | 40 | #define UPDATE_DEFAULT_OPTS "-q" | |
41 | /* until i commit the configure.in patch which gets this, i'll define | ||
42 | * it here as well */ | ||
43 | #ifndef PATH_TO_APTGET | ||
44 | # define PATH_TO_APTGET "/usr/bin/apt-get" | ||
45 | #endif /* PATH_TO_APTGET */ | ||
46 | /* the RE that catches security updates */ | ||
41 | #define SECURITY_RE "^[^\\(]*\\([^ ]* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)" | 47 | #define SECURITY_RE "^[^\\(]*\\([^ ]* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)" |
42 | 48 | ||
43 | /* some standard functions */ | 49 | /* some standard functions */ |
@@ -45,6 +51,8 @@ int process_arguments(int, char **); | |||
45 | void print_help(void); | 51 | void print_help(void); |
46 | void print_usage(void); | 52 | void print_usage(void); |
47 | 53 | ||
54 | /* construct the appropriate apt-get cmdline */ | ||
55 | char* construct_cmdline(upgrade_type u, const char *opts); | ||
48 | /* run an apt-get update */ | 56 | /* run an apt-get update */ |
49 | int run_update(void); | 57 | int run_update(void); |
50 | /* run an apt-get upgrade */ | 58 | /* run an apt-get upgrade */ |
@@ -55,9 +63,12 @@ char* add_to_regexp(char *expr, const char *next); | |||
55 | /* configuration variables */ | 63 | /* configuration variables */ |
56 | static int verbose = 0; /* -v */ | 64 | static int verbose = 0; /* -v */ |
57 | static int do_update = 0; /* whether to call apt-get update */ | 65 | static int do_update = 0; /* whether to call apt-get update */ |
58 | static int dist_upgrade = 0; /* whether to call apt-get dist-upgrade */ | 66 | static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */ |
59 | static char* do_include = NULL; /* regexp to only include certain packages */ | 67 | static char *upgrade_opts = NULL; /* options to override defaults for upgrade */ |
60 | static char* do_exclude = NULL; /* regexp to only exclude certain packages */ | 68 | static char *update_opts = NULL; /* options to override defaults for update */ |
69 | static char *do_include = NULL; /* regexp to only include certain packages */ | ||
70 | static char *do_exclude = NULL; /* regexp to only exclude certain packages */ | ||
71 | static char *do_critical = NULL; /* regexp specifying critical packages */ | ||
61 | 72 | ||
62 | /* other global variables */ | 73 | /* other global variables */ |
63 | static int stderr_warning = 0; /* if a cmd issued output on stderr */ | 74 | static int stderr_warning = 0; /* if a cmd issued output on stderr */ |
@@ -94,7 +105,7 @@ int main (int argc, char **argv) { | |||
94 | printf("APT %s: %d packages available for %s (%d critical updates). %s%s%s%s\n", | 105 | printf("APT %s: %d packages available for %s (%d critical updates). %s%s%s%s\n", |
95 | state_text(result), | 106 | state_text(result), |
96 | packages_available, | 107 | packages_available, |
97 | (dist_upgrade)?"dist-upgrade":"upgrade", | 108 | (upgrade==DIST_UPGRADE)?"dist-upgrade":"upgrade", |
98 | sec_count, | 109 | sec_count, |
99 | (stderr_warning)?" warnings detected":"", | 110 | (stderr_warning)?" warnings detected":"", |
100 | (stderr_warning && exec_warning)?",":"", | 111 | (stderr_warning && exec_warning)?",":"", |
@@ -114,15 +125,18 @@ int process_arguments (int argc, char **argv) { | |||
114 | {"help", no_argument, 0, 'h'}, | 125 | {"help", no_argument, 0, 'h'}, |
115 | {"verbose", no_argument, 0, 'v'}, | 126 | {"verbose", no_argument, 0, 'v'}, |
116 | {"timeout", required_argument, 0, 't'}, | 127 | {"timeout", required_argument, 0, 't'}, |
117 | {"update", no_argument, 0, 'u'}, | 128 | {"update", optional_argument, 0, 'u'}, |
118 | {"dist-upgrade", no_argument, 0, 'd'}, | 129 | {"upgrade", optional_argument, 0, 'U'}, |
119 | {"include", no_argument, 0, 'i'}, | 130 | {"no-upgrade", no_argument, 0, 'n'}, |
120 | {"exclude", no_argument, 0, 'e'}, | 131 | {"dist-upgrade", optional_argument, 0, 'd'}, |
132 | {"include", required_argument, 0, 'i'}, | ||
133 | {"exclude", required_argument, 0, 'e'}, | ||
134 | {"critical", required_argument, 0, 'c'}, | ||
121 | {0, 0, 0, 0} | 135 | {0, 0, 0, 0} |
122 | }; | 136 | }; |
123 | 137 | ||
124 | while(1) { | 138 | while(1) { |
125 | c = getopt_long(argc, argv, "hVvt:udi:e:", longopts, NULL); | 139 | c = getopt_long(argc, argv, "hVvt:u::U::d::ni:e:c:", longopts, NULL); |
126 | 140 | ||
127 | if(c == -1 || c == EOF || c == 1) break; | 141 | if(c == -1 || c == EOF || c == 1) break; |
128 | 142 | ||
@@ -140,10 +154,28 @@ int process_arguments (int argc, char **argv) { | |||
140 | timeout_interval=atoi(optarg); | 154 | timeout_interval=atoi(optarg); |
141 | break; | 155 | break; |
142 | case 'd': | 156 | case 'd': |
143 | dist_upgrade=1; | 157 | upgrade=DIST_UPGRADE; |
158 | if(optarg!=NULL){ | ||
159 | upgrade_opts=strdup(optarg); | ||
160 | if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); | ||
161 | } | ||
162 | break; | ||
163 | case 'U': | ||
164 | upgrade=UPGRADE; | ||
165 | if(optarg!=NULL){ | ||
166 | upgrade_opts=strdup(optarg); | ||
167 | if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); | ||
168 | } | ||
169 | break; | ||
170 | case 'n': | ||
171 | upgrade=NO_UPGRADE; | ||
144 | break; | 172 | break; |
145 | case 'u': | 173 | case 'u': |
146 | do_update=1; | 174 | do_update=1; |
175 | if(optarg!=NULL){ | ||
176 | update_opts=strdup(optarg); | ||
177 | if(update_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); | ||
178 | } | ||
147 | break; | 179 | break; |
148 | case 'i': | 180 | case 'i': |
149 | do_include=add_to_regexp(do_include, optarg); | 181 | do_include=add_to_regexp(do_include, optarg); |
@@ -151,6 +183,9 @@ int process_arguments (int argc, char **argv) { | |||
151 | case 'e': | 183 | case 'e': |
152 | do_exclude=add_to_regexp(do_exclude, optarg); | 184 | do_exclude=add_to_regexp(do_exclude, optarg); |
153 | break; | 185 | break; |
186 | case 'c': | ||
187 | do_critical=add_to_regexp(do_critical, optarg); | ||
188 | break; | ||
154 | default: | 189 | default: |
155 | /* print short usage statement if args not parsable */ | 190 | /* print short usage statement if args not parsable */ |
156 | usage_va(_("Unknown argument - %s"), optarg); | 191 | usage_va(_("Unknown argument - %s"), optarg); |
@@ -174,27 +209,51 @@ found in Debian GNU/Linux\n\ | |||
174 | printf(_(UT_HELP_VRSN)); | 209 | printf(_(UT_HELP_VRSN)); |
175 | printf(_(UT_TIMEOUT), timeout_interval); | 210 | printf(_(UT_TIMEOUT), timeout_interval); |
176 | printf(_("\n\ | 211 | printf(_("\n\ |
177 | -d, --dist-upgrade\n\ | 212 | -U, --upgrade=OPTS\n\ |
178 | Perform a dist-upgrade instead of normal upgrade.\n\ | 213 | [Default] Perform an upgrade. If an optional OPTS argument is provided,\n\ |
214 | apt-get will be run with these command line options instead of the\n\ | ||
215 | default (%s).\n\ | ||
216 | Note that you may be required to have root privileges if you do not use\n\ | ||
217 | the default options.\n\ | ||
218 | -d, --dist-upgrade=OPTS\n\ | ||
219 | Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS\n\ | ||
220 | can be provided to override the default options.\n\ | ||
221 | -n, --no-upgrade\n\ | ||
222 | Do not run the upgrade. Probably not useful (without -u at least).\n\ | ||
179 | -i, --include=REGEXP\n\ | 223 | -i, --include=REGEXP\n\ |
180 | Include only packages matching REGEXP. Can be specified multiple times;\n\ | 224 | Include only packages matching REGEXP. Can be specified multiple times;\n\ |
181 | the values will be combined together. Default is to include all packages.\n\ | 225 | the values will be combined together. Any patches matching this list\n\ |
226 | cause the plugin to return WARNING status. Others will be ignored.\n\ | ||
227 | Default is to include all packages.\n\ | ||
182 | -e, --exclude=REGEXP\n\ | 228 | -e, --exclude=REGEXP\n\ |
183 | Exclude packages matching REGEXP from the list of packages that would\n\ | 229 | Exclude packages matching REGEXP from the list of packages that would\n\ |
184 | otherwise be excluded. Can be specified multiple times; the values\n\ | 230 | otherwise be included. Can be specified multiple times; the values\n\ |
185 | will be combined together. Default is to exclude no packages.\n\n")); | 231 | will be combined together. Default is to exclude no packages.\n\ |
232 | -c, --critical=REGEXP\n\ | ||
233 | If the full package information of any of the upgradable packages match\n\ | ||
234 | this REGEXP, the plugin will return CRITICAL status. Can be specified\n\ | ||
235 | multiple times like above. Default is a regexp matching security\n\ | ||
236 | upgrades for Debian and Ubuntu:\n\ | ||
237 | \t%s\n\ | ||
238 | Note that the package must first match the include list before its\n\ | ||
239 | information is compared against the critical list.\n\ | ||
240 | \n\n"), | ||
241 | UPGRADE_DEFAULT_OPTS, SECURITY_RE); | ||
186 | printf(_("\ | 242 | printf(_("\ |
187 | The following options require root privileges and should be used with care: \ | 243 | The following options require root privileges and should be used with care: \ |
188 | \n\n")); | 244 | \n\n")); |
189 | printf(_("\ | 245 | printf(_("\ |
190 | -u, --update\n\ | 246 | -u, --update=OPTS\n\ |
191 | First perform an 'apt-get update' (note: you may also need to use -t)\ | 247 | First perform an 'apt-get update'. An optional OPTS parameter overrides\n\ |
248 | the default options. Note: you may also need to adjust the global \n\ | ||
249 | timeout (with -t) to prevent the plugin from timing out if apt-get\n\ | ||
250 | upgrade is expected to take longer than the default timeout.\n\ | ||
192 | \n\n")); | 251 | \n\n")); |
193 | } | 252 | } |
194 | 253 | ||
195 | /* simple usage heading */ | 254 | /* simple usage heading */ |
196 | void print_usage(void){ | 255 | void print_usage(void){ |
197 | printf ("Usage: %s [-du] [-t timeout]\n", progname); | 256 | printf ("Usage: %s [[-d|-u|-U]opts] [-n] [-t timeout]\n", progname); |
198 | } | 257 | } |
199 | 258 | ||
200 | /* run an apt-get upgrade */ | 259 | /* run an apt-get upgrade */ |
@@ -202,25 +261,23 @@ int run_upgrade(int *pkgcount, int *secpkgcount){ | |||
202 | int i=0, result=STATE_UNKNOWN, regres=0, pc=0, spc=0; | 261 | int i=0, result=STATE_UNKNOWN, regres=0, pc=0, spc=0; |
203 | struct output chld_out, chld_err; | 262 | struct output chld_out, chld_err; |
204 | regex_t ireg, ereg, sreg; | 263 | regex_t ireg, ereg, sreg; |
205 | char rerrbuf[64]; | 264 | char *cmdline=NULL, rerrbuf[64]; |
206 | const char *default_include_expr="^Inst"; | 265 | const char *include_ptr=NULL, *crit_ptr=NULL; |
266 | |||
267 | if(upgrade==NO_UPGRADE) return STATE_OK; | ||
207 | 268 | ||
208 | /* compile the regexps */ | 269 | /* compile the regexps */ |
209 | if(do_include!=NULL){ | 270 | if(do_include!=NULL) include_ptr=do_include; |
210 | regres=regcomp(&ireg, do_include, REG_EXTENDED); | 271 | else include_ptr="^Inst"; |
211 | if(regres!=0) { | 272 | if(do_critical!=NULL) crit_ptr=do_critical; |
212 | regerror(regres, &ireg, rerrbuf, 64); | 273 | else crit_ptr=SECURITY_RE; |
213 | die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", | 274 | |
214 | progname, rerrbuf); | 275 | regres=regcomp(&ireg, include_ptr, REG_EXTENDED); |
215 | } | 276 | if(regres!=0) { |
216 | } else { | 277 | regerror(regres, &ireg, rerrbuf, 64); |
217 | regres=regcomp(&ireg, default_include_expr, REG_EXTENDED); | 278 | die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", progname, rerrbuf); |
218 | if(regres!=0) { | ||
219 | regerror(regres, &ireg, rerrbuf, 64); | ||
220 | die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", | ||
221 | progname, rerrbuf); | ||
222 | } | ||
223 | } | 279 | } |
280 | |||
224 | if(do_exclude!=NULL){ | 281 | if(do_exclude!=NULL){ |
225 | regres=regcomp(&ereg, do_exclude, REG_EXTENDED); | 282 | regres=regcomp(&ereg, do_exclude, REG_EXTENDED); |
226 | if(regres!=0) { | 283 | if(regres!=0) { |
@@ -229,21 +286,16 @@ int run_upgrade(int *pkgcount, int *secpkgcount){ | |||
229 | progname, rerrbuf); | 286 | progname, rerrbuf); |
230 | } | 287 | } |
231 | } | 288 | } |
232 | regres=regcomp(&sreg, SECURITY_RE, REG_EXTENDED); | 289 | regres=regcomp(&sreg, crit_ptr, REG_EXTENDED); |
233 | if(regres!=0) { | 290 | if(regres!=0) { |
234 | regerror(regres, &ereg, rerrbuf, 64); | 291 | regerror(regres, &ereg, rerrbuf, 64); |
235 | die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", | 292 | die(STATE_UNKNOWN, "%s: Error compiling regexp: %s", |
236 | progname, rerrbuf); | 293 | progname, rerrbuf); |
237 | } | 294 | } |
238 | 295 | ||
239 | 296 | cmdline=construct_cmdline(upgrade, upgrade_opts); | |
240 | |||
241 | /* run the upgrade */ | 297 | /* run the upgrade */ |
242 | if(dist_upgrade==0){ | 298 | result = np_runcmd(cmdline, &chld_out, &chld_err, 0); |
243 | result = np_runcmd(APTGET_UPGRADE, &chld_out, &chld_err, 0); | ||
244 | } else { | ||
245 | result = np_runcmd(APTGET_DISTUPGRADE, &chld_out, &chld_err, 0); | ||
246 | } | ||
247 | /* apt-get upgrade only changes exit status if there is an | 299 | /* apt-get upgrade only changes exit status if there is an |
248 | * internal error when run in dry-run mode. therefore we will | 300 | * internal error when run in dry-run mode. therefore we will |
249 | * treat such an error as UNKNOWN */ | 301 | * treat such an error as UNKNOWN */ |
@@ -251,7 +303,7 @@ int run_upgrade(int *pkgcount, int *secpkgcount){ | |||
251 | exec_warning=1; | 303 | exec_warning=1; |
252 | result = STATE_UNKNOWN; | 304 | result = STATE_UNKNOWN; |
253 | fprintf(stderr, "'%s' exited with non-zero status.\n", | 305 | fprintf(stderr, "'%s' exited with non-zero status.\n", |
254 | APTGET_UPGRADE); | 306 | cmdline); |
255 | } | 307 | } |
256 | 308 | ||
257 | /* parse the output, which should only consist of lines like | 309 | /* parse the output, which should only consist of lines like |
@@ -276,6 +328,7 @@ int run_upgrade(int *pkgcount, int *secpkgcount){ | |||
276 | pc++; | 328 | pc++; |
277 | if(regexec(&sreg, chld_out.line[i], 0, NULL, 0)==0){ | 329 | if(regexec(&sreg, chld_out.line[i], 0, NULL, 0)==0){ |
278 | spc++; | 330 | spc++; |
331 | if(verbose) printf("*"); | ||
279 | } | 332 | } |
280 | if(verbose){ | 333 | if(verbose){ |
281 | printf("*%s\n", chld_out.line[i]); | 334 | printf("*%s\n", chld_out.line[i]); |
@@ -296,6 +349,10 @@ int run_upgrade(int *pkgcount, int *secpkgcount){ | |||
296 | } | 349 | } |
297 | } | 350 | } |
298 | } | 351 | } |
352 | regfree(&ireg); | ||
353 | regfree(&sreg); | ||
354 | if(do_exclude!=NULL) regfree(&ereg); | ||
355 | free(cmdline); | ||
299 | return result; | 356 | return result; |
300 | } | 357 | } |
301 | 358 | ||
@@ -303,9 +360,11 @@ int run_upgrade(int *pkgcount, int *secpkgcount){ | |||
303 | int run_update(void){ | 360 | int run_update(void){ |
304 | int i=0, result=STATE_UNKNOWN; | 361 | int i=0, result=STATE_UNKNOWN; |
305 | struct output chld_out, chld_err; | 362 | struct output chld_out, chld_err; |
363 | char *cmdline; | ||
306 | 364 | ||
307 | /* run the upgrade */ | 365 | /* run the upgrade */ |
308 | result = np_runcmd(APTGET_UPDATE, &chld_out, &chld_err, 0); | 366 | cmdline = construct_cmdline(NO_UPGRADE, update_opts); |
367 | result = np_runcmd(cmdline, &chld_out, &chld_err, 0); | ||
309 | /* apt-get update changes exit status if it can't fetch packages. | 368 | /* apt-get update changes exit status if it can't fetch packages. |
310 | * since we were explicitly asked to do so, this is treated as | 369 | * since we were explicitly asked to do so, this is treated as |
311 | * a critical error. */ | 370 | * a critical error. */ |
@@ -313,7 +372,7 @@ int run_update(void){ | |||
313 | exec_warning=1; | 372 | exec_warning=1; |
314 | result = STATE_CRITICAL; | 373 | result = STATE_CRITICAL; |
315 | fprintf(stderr, "'%s' exited with non-zero status.\n", | 374 | fprintf(stderr, "'%s' exited with non-zero status.\n", |
316 | APTGET_UPDATE); | 375 | cmdline); |
317 | } | 376 | } |
318 | 377 | ||
319 | if(verbose){ | 378 | if(verbose){ |
@@ -332,6 +391,7 @@ int run_update(void){ | |||
332 | } | 391 | } |
333 | } | 392 | } |
334 | } | 393 | } |
394 | free(cmdline); | ||
335 | return result; | 395 | return result; |
336 | } | 396 | } |
337 | 397 | ||
@@ -352,3 +412,36 @@ char* add_to_regexp(char *expr, const char *next){ | |||
352 | 412 | ||
353 | return re; | 413 | return re; |
354 | } | 414 | } |
415 | |||
416 | char* construct_cmdline(upgrade_type u, const char *opts){ | ||
417 | int len=0; | ||
418 | const char *opts_ptr=NULL, *aptcmd=NULL; | ||
419 | char *cmd=NULL; | ||
420 | |||
421 | switch(u){ | ||
422 | case UPGRADE: | ||
423 | if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS; | ||
424 | else opts_ptr=opts; | ||
425 | aptcmd="upgrade"; | ||
426 | break; | ||
427 | case DIST_UPGRADE: | ||
428 | if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS; | ||
429 | else opts_ptr=opts; | ||
430 | aptcmd="dist-upgrade"; | ||
431 | break; | ||
432 | case NO_UPGRADE: | ||
433 | if(opts==NULL) opts_ptr=UPDATE_DEFAULT_OPTS; | ||
434 | else opts_ptr=opts; | ||
435 | aptcmd="update"; | ||
436 | break; | ||
437 | } | ||
438 | |||
439 | len+=strlen(PATH_TO_APTGET)+1; /* "/usr/bin/apt-get " */ | ||
440 | len+=strlen(opts_ptr)+1; /* "opts " */ | ||
441 | len+=strlen(aptcmd)+1; /* "upgrade\0" */ | ||
442 | |||
443 | cmd=(char*)malloc(sizeof(char)*len); | ||
444 | if(cmd==NULL) die(STATE_UNKNOWN, "malloc failed"); | ||
445 | sprintf(cmd, "%s %s %s", PATH_TO_APTGET, opts_ptr, aptcmd); | ||
446 | return cmd; | ||
447 | } | ||