dsck 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []