3 # check_uptime - check uptime to see how long the system is running.
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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 ############################################################################
27 use vars
qw($opt_V $opt_h $opt_v $verbose $PROGNAME $opt_w $opt_c
29 $lower_warn_threshold $upper_warn_threshold
30 $lower_crit_threshold $upper_crit_threshold
33 use lib "$FindBin::Bin";
34 use utils qw(%ERRORS &print_revision &support &usage );
38 sub process_arguments ();
40 $ENV{'PATH'}='@TRUSTED_PATH@';
43 $PROGNAME = "check_uptime";
44 $state = $ERRORS{'UNKNOWN'};
46 my $uptime_file = "/proc/uptime";
51 Getopt::Long::Configure('bundling');
52 $status = process_arguments();
54 print "ERROR: processing arguments\n";
55 exit $ERRORS{"UNKNOWN"};
59 # Get uptime info from file
61 if ( ! -r $uptime_file ) {
62 print "ERROR: file '$uptime_file' is not readable\n";
63 exit $ERRORS{"UNKNOWN"};
66 if ( ! open FILE, "<", $uptime_file ) {
67 print "ERROR: cannot read from file '$uptime_file'\n";
68 exit $ERRORS{"UNKNOWN"};
71 chomp( my $file_content = <FILE> );
74 print "$uptime_file: $file_content\n" if $verbose;
76 # Get first digit value (without fraction)
77 my ( $uptime_seconds ) = $file_content =~ /^([\d]+)/;
79 # Bail out if value is not numeric
80 if ( $uptime_seconds !~ /^\d+$/ ) {
81 print "ERROR: no numeric value: $uptime_seconds\n";
82 exit $ERRORS{"UNKNOWN"};
86 # Do calculations for a "pretty" format (2 weeks, 5 days, ...)
88 my ( $secs, $mins, $hours, $days, $weeks );
89 $secs = $uptime_seconds;
90 $mins = $hours = $days = $weeks = 0;
92 $mins = int( $secs / 60 );
96 $hours = int( $mins / 60 );
100 $days = int( $hours / 24 );
101 $hours -= $days * 24;
104 $weeks = int( $days / 7 );
108 my $pretty_uptime = "";
109 $pretty_uptime .= sprintf( "%d week%s, ", $weeks, $weeks == 1 ? "" : "s" ) if $weeks;
110 $pretty_uptime .= sprintf( "%d day%s, ", $days, $days == 1 ? "" : "s" ) if $days;
111 $pretty_uptime .= sprintf( "%d hour%s, ", $hours, $hours == 1 ? "" : "s" ) if $hours;
112 $pretty_uptime .= sprintf( "%d minute%s, ", $mins, $mins == 1 ? "" : "s" ) if $mins;
113 # Replace last occurrence of comma with "and"
114 $pretty_uptime =~ s/, $/ and /;
115 # Always print the seconds (though it may be 0 seconds)
116 $pretty_uptime .= sprintf( "%d second%s", $secs, $secs == 1 ? "" : "s" );
119 # Default to catch errors in program
120 my $state_str = "UNKNOWN";
123 my $out_of_bounds_text = "";
124 if ( $uptime_seconds > $upper_crit_threshold ) {
125 $state_str = "CRITICAL";
126 $out_of_bounds_text = "upper crit";
127 } elsif ( $uptime_seconds < $lower_crit_threshold ) {
128 $state_str = "CRITICAL";
129 $out_of_bounds_text = "lower crit";
130 } elsif ( $uptime_seconds > $upper_warn_threshold ) {
131 $state_str = "WARNING";
132 $out_of_bounds_text = "upper warn";
133 } elsif ( $uptime_seconds < $lower_warn_threshold ) {
134 $state_str = "WARNING";
135 $out_of_bounds_text = "lower warn";
140 # Prepare uptime value (seconds or days)
141 my $uptime_text = "";
142 my $uptime_unit = "";
144 $uptime_text = floor($uptime_seconds / 60 / 60 / 24);
145 $uptime_unit = "days";
147 $uptime_text = $uptime_seconds;
148 $uptime_unit = "seconds";
151 $msg = "$state_str: ";
153 $msg .= "Uptime is $uptime_text $uptime_unit. ";
154 $msg .= "Exceeds $out_of_bounds_text threshold. " if $out_of_bounds_text;
155 $msg .= "Running for $pretty_uptime. " if $opt_f;
157 my $up_since = strftime( "%Y-%m-%d %H:%M:%S", localtime( time - $uptime_seconds ) );
158 $msg .= "Running since $up_since. ";
161 $state = $ERRORS{$state_str};
164 print "$msg|uptime=${uptime_seconds}s;$upper_warn_threshold;$upper_crit_threshold;0\n";
168 #####################################
172 sub process_arguments(){
174 ("V" => \$opt_V, "version" => \$opt_V,
175 "v" => \$opt_v, "verbose" => \$opt_v,
176 "h" => \$opt_h, "help" => \$opt_h,
177 "w=s" => \$opt_w, "warning=s" => \$opt_w, # warning if above this number
178 "c=s" => \$opt_c, "critical=s" => \$opt_c, # critical if above this number
179 "f" => \$opt_f, "for" => \$opt_f, # show "running for ..."
180 "s" => \$opt_s, "since" => \$opt_s, # show "running since ..."
181 "d" => \$opt_d, "days" => \$opt_d, # report uptime in days
185 print_revision($PROGNAME,'@NP_VERSION@');
186 exit $ERRORS{'UNKNOWN'};
191 exit $ERRORS{'UNKNOWN'};
194 if (defined $opt_v) {
198 unless ( defined $opt_w && defined $opt_c ) {
200 exit $ERRORS{'UNKNOWN'};
203 # Check if a range was supplied ("lowvalue:highvalue") for warning and critical
204 # Otherwise, set 0 as the lower threshold and the parameter value as upper threshold
205 # (the uptime should always be positive, so there should be no issue)
206 if ( $opt_w =~ /^(.+):(.+)$/ ) {
207 $lower_warn_threshold = $1;
208 $upper_warn_threshold = $2;
210 $lower_warn_threshold = 0;
211 $upper_warn_threshold = $opt_w;
213 if ( $opt_c =~ /^(.+):(.+)$/ ) {
214 $lower_crit_threshold = $1;
215 $upper_crit_threshold = $2;
217 $lower_crit_threshold = 0;
218 $upper_crit_threshold = $opt_c;
221 # Set as seconds (calculate if suffix present)
222 $lower_warn_threshold = calc_as_seconds( $lower_warn_threshold );
223 $lower_crit_threshold = calc_as_seconds( $lower_crit_threshold );
224 $upper_warn_threshold = calc_as_seconds( $upper_warn_threshold );
225 $upper_crit_threshold = calc_as_seconds( $upper_crit_threshold );
227 # Check for numeric value of warning parameter
228 if ( $lower_warn_threshold !~ /^\d+$/ ) {
229 print "Lower warning (-w) is not numeric\n";
230 exit $ERRORS{'UNKNOWN'};
232 if ( $upper_warn_threshold !~ /^\d+$/ ) {
233 print "Upper warning (-w) is not numeric\n";
234 exit $ERRORS{'UNKNOWN'};
236 # Check for numeric value of critical parameter
237 if ( $lower_crit_threshold !~ /^\d+$/ ) {
238 print "Lower critical (-c) is not numeric\n";
239 exit $ERRORS{'UNKNOWN'};
241 if ( $upper_crit_threshold !~ /^\d+$/ ) {
242 print "Upper critical (-c) is not numeric\n";
243 exit $ERRORS{'UNKNOWN'};
247 if ( $upper_warn_threshold >= $upper_crit_threshold ) {
248 print "Upper Warning (-w) cannot be greater than Critical (-c)!\n";
249 exit $ERRORS{'UNKNOWN'};
251 # No "<=" since both values are zero if no range (only upper threshold values) is given
252 if ( $lower_warn_threshold < $lower_crit_threshold ) {
253 print "Lower Warning (-w) cannot be less than Critical (-c)!\n";
254 exit $ERRORS{'UNKNOWN'};
257 return $ERRORS{'OK'};
261 print "Usage: $PROGNAME -w <warn> -c <crit> [-v]\n";
265 print_revision($PROGNAME,'@NP_VERSION@');
266 print "Copyright (c) 2002 Subhendu Ghosh/Carlos Canau/Benjamin Schmid\n";
267 print "Copyright (c) 2018 Bernd Arnold\n";
271 print " Checks the uptime of the system using $uptime_file\n";
273 print "-w (--warning) = Min. number of uptime to generate warning\n";
274 print "-c (--critical) = Min. number of uptime to generate critical alert ( w < c )\n";
275 print "-f (--for) = Show uptime in a pretty format (Running for x weeks, x days, ...)\n";
276 print "-s (--since) = Show last boot in yyyy-mm-dd HH:MM:SS format (output from 'uptime -s')\n";
277 print "-d (--days) = Show uptime in days\n";
278 print "-h (--help)\n";
279 print "-V (--version)\n";
280 print "-v (--verbose) = debugging output\n";
282 print "Note: -w and -c are required arguments.\n";
283 print " You can suffix both values with s for seconds (default), m (minutes), h (hours), d (days) or w (weeks).\n";
285 print "Range support: You may specify a range for both warning and critical thresholds.\n";
286 print " This works without additional Perl modules.\n";
287 print "Example: ./check_uptime -w 10m:4w -c 1m:8w\n";
288 print " Results in a critical state when uptime is below 60 seconds or higher than 8 weeks,\n";
289 print " and in a warning state when uptime is below 10 minutes or above 4 weeks.\n";
294 sub calc_as_seconds () {
296 my $parameter = shift;
298 # Check if suffix is present
299 # Calculate parameter to seconds (to get an integer value finally)
300 # If no suffix is present, just return the value
308 my %factor = ( "s" => 1,
312 "w" => 60 * 60 * 24 * 7,
315 if ( $parameter =~ /^(\d+)([a-z])$/ ) {
318 print "detected: value=$value, suffix=$suffix\n" if $verbose;
319 if ( ! defined $factor{$suffix} ) {
320 print "Error: wrong suffix ($suffix) for value '$parameter'";
321 exit $ERRORS{'UNKNOWN'};
323 $parameter = $value * $factor{$suffix};