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.c148
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 */
38int process_arguments(int, char **); 42int process_arguments(int, char **);
39void print_help(void); 43void print_help(void);
40void print_usage(void); 44void print_usage(void);
41 45
46/* run an apt-get update */
42int run_update(void); 47int run_update(void);
48/* run an apt-get upgrade */
43int run_upgrade(int *pkgcount); 49int run_upgrade(int *pkgcount);
50/* add another clause to a regexp */
51char* add_to_regexp(char *expr, const char *next);
52
53/* configuration variables */
54static int verbose = 0; /* -v */
55static int do_update = 0; /* whether to call apt-get update */
56static int dist_upgrade = 0; /* whether to call apt-get dist-upgrade */
57static char* do_include = NULL; /* regexp to only include certain packages */
58static char* do_exclude = NULL; /* regexp to only exclude certain packages */
44 59
45static int verbose = 0; 60/* other global variables */
46static int do_update = 0; 61static int stderr_warning = 0; /* if a cmd issued output on stderr */
47static int dist_upgrade = 0; 62static int exec_warning = 0; /* if a cmd exited non-zero */
48static int stderr_warning = 0;
49static int exec_warning = 0;
50 63
51int main (int argc, char **argv) { 64int 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(_("\
157The following options require root privileges and should be used with care: \ 182The 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 */
171int run_upgrade(int *pkgcount){ 196int 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
322char* 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}