summaryrefslogtreecommitdiffstats
path: root/plugins/check_apt.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_apt.c')
-rw-r--r--plugins/check_apt.c195
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. */ 36typedef 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 **);
45void print_help(void); 51void print_help(void);
46void print_usage(void); 52void print_usage(void);
47 53
54/* construct the appropriate apt-get cmdline */
55char* construct_cmdline(upgrade_type u, const char *opts);
48/* run an apt-get update */ 56/* run an apt-get update */
49int run_update(void); 57int 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 */
56static int verbose = 0; /* -v */ 64static int verbose = 0; /* -v */
57static int do_update = 0; /* whether to call apt-get update */ 65static int do_update = 0; /* whether to call apt-get update */
58static int dist_upgrade = 0; /* whether to call apt-get dist-upgrade */ 66static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */
59static char* do_include = NULL; /* regexp to only include certain packages */ 67static char *upgrade_opts = NULL; /* options to override defaults for upgrade */
60static char* do_exclude = NULL; /* regexp to only exclude certain packages */ 68static char *update_opts = NULL; /* options to override defaults for update */
69static char *do_include = NULL; /* regexp to only include certain packages */
70static char *do_exclude = NULL; /* regexp to only exclude certain packages */
71static char *do_critical = NULL; /* regexp specifying critical packages */
61 72
62/* other global variables */ 73/* other global variables */
63static int stderr_warning = 0; /* if a cmd issued output on stderr */ 74static 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(_("\
187The following options require root privileges and should be used with care: \ 243The 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 */
196void print_usage(void){ 255void 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){
303int run_update(void){ 360int 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
416char* 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}