867fe41e251938a8abed79d20289583c0ee0a2b9
1 /******************************************************************************
2 * check_apt.c: check for available updates in apt package management systems
3 * original author: sean finney <seanius@seanius.net>
4 * (with some common bits stolen from check_nagios.c)
5 ******************************************************************************
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 $Id$
23 ******************************************************************************/
25 const char *progname = "check_apt";
26 const char *revision = "$Revision$";
27 const char *copyright = "2006";
28 const char *email = "nagiosplug-devel@lists.sourceforge.net";
30 #include "common.h"
31 #include "runcmd.h"
32 #include "utils.h"
34 #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"
36 #define APTGET_UPDATE "/usr/bin/apt-get -q update"
38 int process_arguments(int, char **);
39 void print_help(void);
40 void print_usage(void);
42 int run_update(void);
43 int run_upgrade(int *pkgcount);
45 static int verbose = 0;
46 static int do_update = 0;
47 static int dist_upgrade = 0;
48 static int stderr_warning = 0;
49 static int exec_warning = 0;
51 int main (int argc, char **argv) {
52 int result=STATE_UNKNOWN, packages_available=0;
54 if (process_arguments(argc, argv) == ERROR)
55 usage_va(_("Could not parse arguments"));
57 /* Set signal handling and alarm timeout */
58 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
59 usage_va(_("Cannot catch SIGALRM"));
60 }
62 /* handle timeouts gracefully... */
63 alarm (timeout_interval);
65 /* if they want to run apt-get update first... */
66 if(do_update) result = run_update();
68 /* apt-get upgrade */
69 result = max_state(result, run_upgrade(&packages_available));
71 if(stderr_warning){
72 fprintf(stderr, "warning, output detected on stderr. ");
73 fprintf(stderr, "re-run with -v for more information.\n");
74 }
76 if(packages_available > 0){
77 result = max_state(result, STATE_WARNING);
78 } else {
79 result = max_state(result, STATE_OK);
80 }
82 printf("APT %s: %d packages available for %s.%s%s%s\n",
83 state_text(result),
84 packages_available,
85 (dist_upgrade)?"dist-upgrade":"upgrade",
86 (stderr_warning)?" (warnings detected)":"",
87 (stderr_warning && exec_warning)?",":"",
88 (exec_warning)?" (errors detected)":""
89 );
91 return result;
92 }
94 /* process command-line arguments */
95 int process_arguments (int argc, char **argv) {
96 int c;
98 static struct option longopts[] = {
99 {"version", no_argument, 0, 'V'},
100 {"help", no_argument, 0, 'h'},
101 {"verbose", no_argument, 0, 'v'},
102 {"timeout", required_argument, 0, 't'},
103 {"update", no_argument, 0, 'u'},
104 {"dist-upgrade", no_argument, 0, 'd'},
105 {0, 0, 0, 0}
106 };
108 while(1) {
109 c = getopt_long(argc, argv, "hVvt:ud", longopts, NULL);
111 if(c == -1 || c == EOF || c == 1) break;
113 switch(c) {
114 case 'h': /* help */
115 print_help();
116 exit(STATE_OK);
117 case 'V': /* version */
118 print_revision(progname, revision);
119 exit(STATE_OK);
120 case 'v':
121 verbose++;
122 break;
123 case 't':
124 timeout_interval=atoi(optarg);
125 break;
126 case 'd':
127 dist_upgrade=1;
128 break;
129 case 'u':
130 do_update=1;
131 break;
132 default:
133 /* print short usage statement if args not parsable */
134 usage_va(_("Unknown argument - %s"), optarg);
135 }
136 }
138 return OK;
139 }
142 /* informative help message */
143 void print_help(void){
144 print_revision(progname, revision);
145 printf(_(COPYRIGHT), copyright, email);
146 printf(_("\
147 This plugin checks for software updates on systems that use\n\
148 package management systems based on the apt-get(8) command\n\
149 found in Debian GNU/Linux\n\
150 \n\n"));
151 print_usage();
152 printf(_(UT_HELP_VRSN));
153 printf(_(UT_TIMEOUT), timeout_interval);
154 printf(_("\n\
155 -d, --dist-upgrade\n\
156 Perform a dist-upgrade instead of normal upgrade.\n\n\
157 The following options require root privileges and should be used with care: \
158 \n\n"));
159 printf(_("\
160 -u, --update\n\
161 First perform an 'apt-get update' (note: you may also need to use -t)\
162 \n\n"));
163 }
165 /* simple usage heading */
166 void print_usage(void){
167 printf ("Usage: %s [-du] [-t timeout]\n", progname);
168 }
170 /* run an apt-get upgrade */
171 int run_upgrade(int *pkgcount){
172 int i=0, result=STATE_UNKNOWN, pc=0;
173 struct output chld_out, chld_err;
175 /* run the upgrade */
176 if(dist_upgrade==0){
177 result = np_runcmd(APTGET_UPGRADE, &chld_out, &chld_err, 0);
178 } else {
179 result = np_runcmd(APTGET_DISTUPGRADE, &chld_out, &chld_err, 0);
180 }
181 /* apt-get only changes exit status if there is an internal error */
182 if(result != 0){
183 exec_warning=1;
184 result = STATE_UNKNOWN;
185 fprintf(stderr, "'%s' exited with non-zero status.\n%s\n",
186 APTGET_UPGRADE,
187 "Run again with -v for more info.");
188 }
190 /* parse the output, which should only consist of lines like
191 *
192 * Inst package ....
193 * Conf package ....
194 *
195 * so we'll filter based on "Inst". If we ever want to do
196 */
197 for(i = 0; i < chld_out.lines; i++) {
198 if(strncmp(chld_out.line[i], "Inst", 4)==0){
199 if(verbose){
200 printf("%s\n", chld_out.line[i]);
201 }
202 pc++;
203 }
204 }
205 *pkgcount=pc;
207 /* If we get anything on stderr, at least set warning */
208 if(chld_err.buflen){
209 stderr_warning=1;
210 result = max_state(result, STATE_WARNING);
211 if(verbose){
212 for(i = 0; i < chld_err.lines; i++) {
213 printf("%s\n", chld_err.line[i]);
214 }
215 }
216 }
217 return result;
218 }
220 /* run an apt-get update (needs root) */
221 int run_update(void){
222 int i=0, result=STATE_UNKNOWN;
223 struct output chld_out, chld_err;
225 /* run the upgrade */
226 result = np_runcmd(APTGET_UPDATE, &chld_out, &chld_err, 0);
227 /* apt-get only changes exit status if there is an internal error */
228 if(result != 0){
229 exec_warning=1;
230 result = STATE_UNKNOWN;
231 fprintf(stderr, "'%s' exited with non-zero status.\n",
232 APTGET_UPDATE);
233 }
235 if(verbose){
236 for(i = 0; i < chld_out.lines; i++) {
237 printf("%s\n", chld_out.line[i]);
238 }
239 }
241 /* If we get anything on stderr, at least set warning */
242 if(chld_err.buflen){
243 stderr_warning=1;
244 result = max_state(result, STATE_WARNING);
245 if(verbose){
246 for(i = 0; i < chld_err.lines; i++) {
247 printf("%s\n", chld_err.line[i]);
248 }
249 }
250 }
251 return result;
252 }