dsck 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +52 -0
  3. data/README.rdoc +67 -0
  4. data/bin/dsck +364 -0
  5. data/bin/dsck2mail +14 -0
  6. metadata +50 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 309e08b8cf2110b0e51aec6ea2f170837a18fb7a
4
+ data.tar.gz: 4028dbb530b0c0159fe54da5e52053187ba86cc4
5
+ SHA512:
6
+ metadata.gz: 1b5b5c24705cab978ddd271f422227eaeb857f02ae393ed0e992dbc2c4f28c313d5a73836d9675de6a2f8b458d57426a4b6510a0cbbe6de27dc2588fcad66363
7
+ data.tar.gz: 0877cb109f1d0980b6c2e6eecca577956b6a11d6d31826fc47aeeb389c503fee69df216d2581fa07655a829b1f61cb9d32430e81d56889558a97689f62ad650f
@@ -0,0 +1,52 @@
1
+ 2014-10-08 Tatsuki Sugiura <sugi@nemui.org>
2
+
3
+ * Drop filesystem module, now just parsing df output.
4
+ * Change dist style to rubygems
5
+ * License has been changed to GPL-3
6
+
7
+ 2004-01-14 Tatsuki Sugiura <sugi@nemui.org>
8
+
9
+ * release 2.0.7
10
+
11
+ * dsck2mail: fixup abort on errors.
12
+
13
+ 2003-09-21 Tatsuki Sugiura <sugi@nemui.org>
14
+
15
+ * release 2.0.6
16
+
17
+ * dsck: small for ruby 1.8
18
+
19
+ 2003-07-31 Tatsuki Sugiura <sugi@nemui.org>
20
+
21
+ * release 2.0.5
22
+
23
+ * dsck: exit with 1 if errors. better option handling.
24
+
25
+ 2003-04-16 Tatsuki Sugiura <sugi@nemui.org>
26
+
27
+ * release 2.0.4
28
+
29
+ * dsck: ignore linux bind mount.
30
+
31
+ 2003-04-07 Tatsuki Sugiura <sugi@nemui.org>
32
+
33
+ * release 2.0.3
34
+
35
+ * dsck: report format changed. good looking with folding.
36
+
37
+ 2003-02-03 Tatsuki Sugiura <sugi@nemui.org>
38
+
39
+ * release 2.0.2
40
+
41
+ * fix typo in report
42
+
43
+ * fix Makefile.am for distclean error
44
+
45
+ 2002-07-31 Tatsuki Sugiura <sugi@nemui.org>
46
+
47
+ * add dsck2mail script
48
+
49
+ 2002-07-31 Tatsuki Sugiura <sugi@nemui.org>
50
+
51
+ * Initial release with ruby.
52
+
@@ -0,0 +1,67 @@
1
+ = dsck
2
+
3
+ == What's this?
4
+
5
+ Simple disk space checker
6
+
7
+ == System requirement
8
+
9
+ * ruby (1.8+)
10
+ * can execute "df -k"
11
+
12
+ == Install
13
+
14
+ gem install dsck
15
+
16
+ == Support scripts
17
+
18
+ * dsck2mail - sample shell wrapper script for crontab.
19
+
20
+ == Usage
21
+
22
+ See "rd2 dsck" or "dsck -h" for details.
23
+
24
+ dsck [-Vhv] [-c config | global_threshold | /mount/point threshold]...
25
+
26
+ === Options
27
+
28
+ [-V, +--version+] Show version
29
+ [-h, +--help+] Show this message
30
+ [-v, +--verbose+] Verbose output. Multiple -v to increase verbosity
31
+ [-q, +--quiet+] Quiet output. Multiple -q to decrease verbosity
32
+ [-s, +--summary+] Show summary report
33
+ [-r, +--report+] Show detail report
34
+ [-e, +--errors-only+] Suppress "-r" and "-s" when nothing to alert
35
+ [-c _conf_, +--config=+_conf_] Specify config file (arguments prevail over config)
36
+
37
+ If both of "-s" or "-r" are not specified, fallback to "-se".
38
+
39
+ === Threshold Format
40
+
41
+ If argument is matched regex "/[0-9]+\[%BKMGT]?/" or
42
+ "nocheck", it's considerd as threshold.
43
+
44
+ Suffix character was consider as *B*=byte, *K*=KiloByte, *M*=Megabyte,
45
+ *G*=GigaByte, *T*=TeraByte, *P*=PetaByte and %=Percent.
46
+
47
+ When string has no suffix character, longer than *3* will
48
+ be treated as *KiloByte*, if not as *percent*.
49
+
50
+ This script alert when use% is *over* threshold of percentage or
51
+ filesystem available size is *under* threshold of Byte and blocks.
52
+
53
+ === ConfigFile Format
54
+
55
+ Same as command line arguments.
56
+
57
+ Especially, after "#" until end-of-line is considerd as comment.
58
+
59
+ === Example
60
+
61
+ dsck -serv "95%" / 50M /tmp 5 /var/spool/squid nocheck
62
+
63
+ This means
64
+ * Verbose output (+1)
65
+ * Show summary and detail when error happened
66
+ * Global threshold is 95%, "/" is 50MByte, "/tmp" is 5%
67
+ * "/var/spool/squid" will not be checked
@@ -0,0 +1,364 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ #
5
+ # dsck - Simple disk space checker
6
+ #
7
+ # Copyright: Tatsuki Sugiura <sugi@nemui.org>
8
+ # License: GPL-3
9
+ #
10
+
11
+ =begin
12
+
13
+ = NAME
14
+
15
+ ((:dsck:)) - simple disk space checker
16
+
17
+ = SYNOPSIS
18
+
19
+ ((%dsck [-Vhv] [-c config | global_threshold | /mount/point threshold]...%))
20
+
21
+ = DESCRIPTION
22
+
23
+ == Options
24
+
25
+ If both "-s" and "-r" not specified, set "-se" automatically.
26
+
27
+ : -V, --version
28
+ Show version
29
+ : -h, --help
30
+ Show this message
31
+ : -v, --verbose
32
+ Verbose output. Multiple -v to increase verbosity
33
+ : -q, --quiet
34
+ Quiet output. Multiple -q to decrease verbosity
35
+ : -s, --summary
36
+ Show summary report
37
+ : -r, --report
38
+ Show detail report
39
+ : -e, --errors-only
40
+ Suppress "-r" and "-s" when nothing to alert
41
+ : -c ((|conf|)), --config=((|conf|))
42
+ Specify config file (arguments prevail over config)
43
+
44
+ == Threshold Format
45
+
46
+ If argument is matched regex (({/[0-9]+([BKMGTb%])?/})) or
47
+ "nocheck", it's considerd as threshold.
48
+
49
+ Suffix character was consider as ((*B*))=byte, ((*K*))=KiloByte, ((*M*))=Megabyte,
50
+ ((*G*))=GigaByte, ((*T*))=TeraByte, ((*P*))=PetaByte and ((*%*))=Percent.
51
+
52
+ When string has no suffix character, longer than ((*3*)) will
53
+ be considered ((*KiloByte*)), if not ((*Percent*)).
54
+
55
+ This script alert when use% is ((*over*)) threshold of percentage or
56
+ filesystem available size is ((*under*)) threshold of Byte and blocks.
57
+
58
+ == ConfigFile Format
59
+
60
+ Same as command line arguments.
61
+
62
+ Especially, after "#" until end-of-line is considerd as comment.
63
+
64
+ = Example
65
+
66
+ ((%dsck -serv "95%" / 50M /tmp 5 /var/spool/squid nocheck%))
67
+
68
+ This means
69
+ * Verbose output (+1)
70
+ * Show summary and detail when error happened
71
+ * Global threshold is 95%, "/" is 50MByte, "/tmp" is 5%
72
+ * "/var/spool/squid" will not be checked
73
+
74
+ =end
75
+
76
+
77
+ require 'getoptlong'
78
+ require 'ostruct'
79
+
80
+ $MYNAME = File.basename($0)
81
+ $VERSION = "3.0.0"
82
+
83
+ ##
84
+ ## classes
85
+ ##
86
+ class DiskSpaceCheker < Hash
87
+ class NonExistMountPoint < StandardError; end
88
+ class InvalidThreshold < StandardError; end
89
+ DF_COLS = %w(device size used avail use_per mount)
90
+
91
+ def initialize (global_threshold = "90%")
92
+ @mounts = read_mounts
93
+ @global_threshold = thres_normalizer(global_threshold)
94
+ end
95
+
96
+ def read_mounts
97
+ mounts_dev = {}
98
+ lno = 0
99
+ `df -k`.each_line do |line|
100
+ lno += 1
101
+ lno == 1 and next
102
+ cols = line.split(/\s+/)
103
+ dev = cols.first
104
+ dev == "" and
105
+ cols[0] = dev = mounts_dev.keys.last
106
+ mounts_dev[dev] ||= OpenStruct.new
107
+ DF_COLS.each_with_index do |c, i|
108
+ v = case c
109
+ when "size", "avail", "used"
110
+ cols[i].to_i * 1024
111
+ else
112
+ cols[i]
113
+ end
114
+ mounts_dev[dev].send("#{c}=", v)
115
+ end
116
+ end
117
+ mounts = {}
118
+ mounts_dev.each {|dev, m|
119
+ mounts[m.mount] = m
120
+ }
121
+ mounts
122
+ end
123
+
124
+ def []=(key, val)
125
+ unless @mounts.has_key?(key)
126
+ raise NonExistMountPoint
127
+ end
128
+ val = thres_normalizer(val)
129
+ super
130
+ end
131
+
132
+ def [](mount)
133
+ self.has_key?(mount) ? super : @global_threshold
134
+ end
135
+
136
+ def need_alert?
137
+ @mounts.each { |mount, minfo|
138
+ if over?(mount)
139
+ return true
140
+ end
141
+ }
142
+ false
143
+ end
144
+ alias error? need_alert?
145
+
146
+ def global_threshold=(thres)
147
+ @global_threshold = thres_normalizer(thres)
148
+ end
149
+
150
+ def thres_normalizer(thres)
151
+ if thres !~ /^\d+[BKMGTP%]?$/ && thres != "nocheck"
152
+ raise InvalidThreshold
153
+ elsif thres !~ /\D/
154
+ if thres.length < 3
155
+ thres = thres + "%"
156
+ else
157
+ thres = thres + "K"
158
+ end
159
+ end
160
+ return thres
161
+ end
162
+
163
+ def over?(mount)
164
+ unless @mounts.has_key?(mount)
165
+ raise NonExistMountPoint, mount
166
+ end
167
+ minfo = @mounts[mount]
168
+ thres = self[mount]
169
+ if thres == "nocheck"
170
+ return false
171
+ elsif thres =~ /^(\d+)%$/
172
+ thres = (minfo.size * (100 - $1.to_f) / 100).to_i
173
+ elsif thres =~ /^(\d+)([BKMGTP])$/
174
+ thres = $1.to_i * (1 << (10 * %w(B K M G T P).index($2).to_i))
175
+ end
176
+ minfo.avail <= thres
177
+ end
178
+
179
+ def summary
180
+ ret = Array.new
181
+ @mounts.each { |m, info|
182
+ if over?(m)
183
+ dev = info.device
184
+ ret.push("Warning: #{dev} (#{m}) " +
185
+ (self[m] =~ /%$/ ? "is used over" : "less than") +
186
+ " #{self[m]}")
187
+ end
188
+ }
189
+ ret.size > 0 ? ret : ["All good."]
190
+ end
191
+
192
+ def report
193
+ ret = [%w(Device Mounted Size Avail Use% Thres Status)]
194
+ @mounts.each { |mount, minfo|
195
+ @mounts.has_key?(mount) or next
196
+ use_per = ((minfo.size - minfo.avail) * 100 / minfo.size).to_i # NOTE: Do NOT use minfo.used due to reserved block
197
+ ret.push [minfo.device, mount,
198
+ human_size(minfo.size), human_size(minfo.avail),
199
+ "#{use_per}%", self[mount],
200
+ over?(mount) ? "=!ALERT!=" : "OK"]
201
+ }
202
+ ret.map{ |r|
203
+ sprintf(%Q[#{ r[0].length < 15 ? "%-15s " : "%s\n#{' '*16}" }], r.shift) +
204
+ sprintf(%Q[#{ r[0].length < 10 ? "%-10s " : "%s\n#{' '*27}" }], r.shift) +
205
+ sprintf("%10s %10s %5s %8s %10s", *r)
206
+ }
207
+ end
208
+
209
+ def human_size(size)
210
+ suffixes = %w(K M G T P)
211
+ suffixes.reverse.each_with_index do |s, i|
212
+ unit = 1 << (10 * (suffixes.length - i))
213
+ size < unit and next
214
+ return sprintf("%0.1f#{s}", size / unit.to_f)
215
+ end
216
+ return size.to_s
217
+ end
218
+
219
+ attr_reader :global_threshold, :mounts
220
+ end
221
+
222
+
223
+ if File.basename(__FILE__) == File.basename($0)
224
+
225
+ $echo_level = 3
226
+
227
+ ##
228
+ ## functions
229
+ ##
230
+
231
+ def version
232
+ puts "#{$MYNAME} version #{$VERSION}. Copyright 2002, Tatsuki Sugiura <sugi@nemui.org>"
233
+ end
234
+
235
+ def usage(io = $stdout)
236
+ io.print <<EOU
237
+ Usage: #{$MYNAME} [-Vhvqsre] [-c config|global_threshold|/mount/point threshold]...
238
+ Options: (default="-se")
239
+ -V, --version show version
240
+ -h, --help show this message
241
+ -v, --verbose verbose output. multiple -v for increase verbosity
242
+ -q, --quiet quiet output. multiple -q for decrease verbosity
243
+ -s, --summary show summary
244
+ -r, --report show detail report
245
+ -e, --errors-only suppress "-r" and "-s" when nothing to alert
246
+ -c conf, --config=conf specify config file (arguments prevail over config)
247
+ EOU
248
+ end
249
+
250
+ def msg(level = 3, *msg)
251
+ # level:
252
+ # 1 fatal error message
253
+ # 2 warning
254
+ # 3 notice, normal message
255
+ # 4 debug output
256
+ # 5- more...
257
+ if $echo_level < level
258
+ return true
259
+ end
260
+ (level < 3 ? $stderr : $stdout).print msg.join
261
+ end
262
+
263
+ ##
264
+ ## main
265
+ ##
266
+
267
+ opt = Hash.new
268
+
269
+ optparser = GetoptLong.new
270
+ optparser.set_options(
271
+ ["--verbose", "-v", GetoptLong::NO_ARGUMENT],
272
+ ["--quiet", "-q", GetoptLong::NO_ARGUMENT],
273
+ ["--help", "-h", GetoptLong::NO_ARGUMENT],
274
+ ["--version", "-V", GetoptLong::NO_ARGUMENT],
275
+ ["--summary", "-s", GetoptLong::NO_ARGUMENT],
276
+ ["--report", "-r", GetoptLong::NO_ARGUMENT],
277
+ ["--errors-only", "-e", GetoptLong::NO_ARGUMENT],
278
+ ["--config", "-c", GetoptLong::REQUIRED_ARGUMENT]
279
+ )
280
+
281
+ begin
282
+ optparser.each_option do |name, arg|
283
+ if name == "--verbose"
284
+ $echo_level += 1
285
+ elsif name == "--quiet"
286
+ $echo_level -= 1
287
+ else
288
+ opt[name.sub(/^--/, '')] = arg
289
+ end
290
+ end
291
+ rescue
292
+ usage($stderr)
293
+ exit(1)
294
+ end
295
+
296
+ if opt["version"]
297
+ version
298
+ exit(0)
299
+ end
300
+
301
+ if opt["help"]
302
+ usage
303
+ exit(0)
304
+ end
305
+
306
+ dsck = DiskSpaceCheker.new
307
+ args = Array.new
308
+
309
+ # read config
310
+ if opt.has_key?("config")
311
+ begin
312
+ File.open(opt["config"]) { |fh|
313
+ fh.each { |line|
314
+ line.sub!(/#.*/,"")
315
+ line.scan(/(\S+)/) { |part|
316
+ args.push(*part)
317
+ }
318
+ }
319
+ }
320
+ rescue
321
+ msg 2, "Error: Can't open config (#{$!}). Ignored.\n"
322
+ end
323
+ end
324
+
325
+ args = args + ARGV
326
+ while arg = args.shift
327
+ if arg =~ /^\d+[BKMGTP%]?$/ || arg == "nocheck"
328
+ dsck.global_threshold = arg
329
+ else
330
+ mount = arg
331
+ threshold = args.shift
332
+ begin
333
+ dsck[mount] = threshold
334
+ rescue DiskSpaceCheker::InvalidThreshold
335
+ msg 2, "Error: Invalid threshold '#{threshold}' for #{mount}. Ignored.\n"
336
+ rescue DiskSpaceCheker::NonExistMountPoint
337
+ msg 2, "Warning: Mount point #{mount} is not found. Ignored.\n"
338
+ end
339
+ end
340
+ end
341
+
342
+ msg 5, "checking thresholds...\n"
343
+ dsck.mounts.each {|m, minfo|
344
+ msg 5, " #{m}\t#{dsck[m]}\n"
345
+ }
346
+
347
+ # set default option
348
+ if !opt.has_key?("summary") && !opt.has_key?("report")
349
+ opt["summary"] = opt["errors-only"] = true
350
+ end
351
+
352
+ if !opt["errors-only"] || dsck.need_alert?
353
+ if opt["summary"]
354
+ msg 4, "=== Problem summary ===\n"
355
+ puts dsck.summary
356
+ end
357
+
358
+ if opt["report"]
359
+ msg 4, "=== Current Status ===\n"
360
+ puts dsck.report
361
+ end
362
+ end
363
+ dsck.error? ? exit(1) : exit(0)
364
+ end
@@ -0,0 +1,14 @@
1
+ #!/bin/sh
2
+
3
+ dsck="`dsck -serv -c /etc/dsck.conf`"
4
+
5
+ test -z "$dsck" && exit 0
6
+
7
+ echo "Subject: === `hostname -s` disk space checker ===
8
+ X-Sender: dsck2mail
9
+ Content-Type: text/plain; charset=us-ascii
10
+
11
+ Alert on `hostname -f`
12
+
13
+ $dsck
14
+ " | sendmail root
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dsck
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tatsuki Sugiura
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Simple disk space checker by parsing df output.
14
+ email: sugi@nemui.org
15
+ executables:
16
+ - dsck
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - README.rdoc
20
+ - ChangeLog
21
+ files:
22
+ - ChangeLog
23
+ - README.rdoc
24
+ - bin/dsck
25
+ - bin/dsck2mail
26
+ homepage: http://github.com/sugi/dsck
27
+ licenses:
28
+ - GPL-3
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.2.2
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Simple disk space checker
50
+ test_files: []