umount-many 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/Rakefile +16 -0
  2. data/TODO +3 -0
  3. data/VERSION +1 -0
  4. data/bin/umount-many +60 -0
  5. data/lib/umount-many.rb +123 -0
  6. metadata +65 -0
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "umount-many"
5
+ gem.executables = "umount-many"
6
+ gem.summary = "Unmount several devices based on filters"
7
+ gem.email = "sin3141592@gmail.com"
8
+ gem.homepage = "http://github.com/hackenporsche/umount-many"
9
+ gem.description = gem.summary
10
+ gem.authors = ["Hagbard Celine"]
11
+ #gem.files = FileList["bin/**/*", "lib/**/*"]
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts "Couldn't load jeweler. Please install it with `gem install jeweler`"
16
+ end
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ - Write a bit of documentation
2
+ - Make a gem out of it
3
+ - Of course fix the TODO's placed in the code
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/umount-many ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'optparse'
5
+ require File.join(File.dirname(__FILE__), "..", "lib", "umount-many")
6
+
7
+ def main
8
+ opts = Hash.new
9
+ OptionParser.new do |opt|
10
+ opt.on("-m", "--mount-point MOUNTPOINT",
11
+ "Unmount all file systems mounted on MOUNTPOINT") do |mp|
12
+ opts[:mount_point] = mp
13
+ end
14
+
15
+ opt.on("-d", "--device DEVICE",
16
+ "Unmount all file system mounted from DEVICE") do |d|
17
+ opts[:device] = d
18
+ end
19
+
20
+ opt.on("-t", "--type TYPE",
21
+ "Unmount all file systems having TYPE as file system") do |t|
22
+ opts[:type] = t
23
+ end
24
+
25
+ opt.on("-o", "--option OPTION",
26
+ "Unmount all file systems having OPTION set") do |o|
27
+ opts[:options] ||= []
28
+ opts[:options] << o
29
+ end
30
+
31
+ opt.on("-a", "--all",
32
+ "Unmount every file system (CAUTION: Can be dangerous)") do
33
+ opts[:all] = true
34
+ end
35
+
36
+ opt.on("-s", "--simulate", "List the file systems to unmount "+
37
+ "but do not unmount anything. See -r as well") do
38
+ opts[:simulate] = true
39
+ end
40
+
41
+ opt.on("-r", "--report FORMAT", "Instead of unmounting anything " +
42
+ "report matched devices to stdout. Differs from -s in " +
43
+ "printing standardized format like Yaml. FORMAT can be " +
44
+ "Yaml, JSON or XML") do |format|
45
+ opts[:reporting] = format
46
+ end
47
+
48
+ opt.on("-v", "--verbose", "Print currently unmounted device") do
49
+ opts[:verbose] = true
50
+ end
51
+
52
+ opt.on("-R", "--reverse", "Reverse the list of devices. Last mounted " +
53
+ "devices are unmounted first") do
54
+ opts[:reverse] = true
55
+ end
56
+ end.parse!
57
+ unmount_many_fs(opts)
58
+ end
59
+
60
+ main if $0 == __FILE__
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ # == umount-many
5
+ # umount-many allows you to unmount several file systems at once
6
+ # You can specify several filter types to select the desired file systems
7
+ # For example:
8
+ # +umount-many -t ext4+
9
+ # This command unmounts every file system that has ext4 as file system type
10
+ # For a list of all filters use the +-h+ or +--help+ command line option
11
+
12
+ require 'optparse'
13
+ require 'set'
14
+
15
+ class Hash
16
+ # Works similiar to the +values_at+ method but return
17
+ # instead of just values an appropriate hash
18
+ def hash_at(*keys)
19
+ hash = Hash.new
20
+ keys.zip(self.values_at(*keys)).each {|k, v| hash[k] = v}
21
+ hash
22
+ end
23
+ end
24
+
25
+ def parse_file_systems
26
+ # TODO: Currently calls +mount+ and parses stdout. Not such a good
27
+ # approach, is it?
28
+ # TODO: I just can the regex gurantee to work for my box (which is a linux
29
+ # 2.6.31 with +mount+ from util-linux-ng 2.16)
30
+
31
+ filesystems = []
32
+ IO.popen("mount") do |pipe|
33
+ pipe.each_line do |line|
34
+ if line =~ /([^\s]+) on ([^\s]+) type ([^\s]+) \((.*)\)/
35
+ filesystems.push({:device => $1, :mount_point => $2, :type => $3,
36
+ :options => $4.split(",")})
37
+ else
38
+ STDERR.puts("Couldn't parse output from mount. " +
39
+ "Skipping current line")
40
+ end
41
+ end
42
+ end
43
+ filesystems
44
+ end
45
+
46
+ def filter_by_device(filesystems, device)
47
+ filesystems.select {|e| e[:device] == device}
48
+ end
49
+
50
+ def filter_by_mount_point(filesystems, mp)
51
+ filesystems.select {|e| e[:mount_point] == mp}
52
+ end
53
+
54
+ def filter_by_type(filesystems, type)
55
+ filesystems.select {|e| e[:type].downcase == type.downcase}
56
+ end
57
+
58
+ def filter_by_options(filesystems, option)
59
+ filesystems.select {|e| e[:options].include?(option)}
60
+ end
61
+
62
+ def collect_filters(opts)
63
+ filters = []
64
+ opts.hash_at(:mount_point, :device, :type, :options).each do |filter, v|
65
+ filters.push filter if v && !v.empty?
66
+ end
67
+ filters.map{|e| [method("filter_by_" + e.to_s), e]}
68
+ end
69
+
70
+ def report_results(to_unmount, format)
71
+ unless ["yaml", "json", "xml"].include?(format)
72
+ puts "Not a supported format for reporting: #{format}"
73
+ puts "See the help (-h) for a list"
74
+ exit 2
75
+ end
76
+ if format.downcase == "xml"
77
+ # TODO: I am not quite sure if XmlSimple makes proper output
78
+ STDERR.puts "WARNING: XML format is experimental."
79
+ require 'xmlsimple'
80
+ puts XmlSimple.xml_out(to_unmount)
81
+ else
82
+ require format
83
+ meth = to_unmount.method("to_" + format)
84
+ puts meth.call
85
+ end
86
+ end
87
+
88
+ def unmount_devices(devices, verbose)
89
+ devices.each do |device|
90
+ if verbose
91
+ print ("Unmounting #{device[:device]} mounted on " +
92
+ "#{device[:mount_point]}... ")
93
+ end
94
+ system "umount \"#{device[:device]}\""
95
+ # Needed because umount takes a bit of time
96
+ sleep 0.2
97
+ puts "DONE" if verbose
98
+ end
99
+ end
100
+
101
+ def matched_devices(opts)
102
+ filesystems = parse_file_systems
103
+ filters = collect_filters(opts)
104
+ to_unmount = Set.new
105
+ results = filters.map {|meth, name| meth.call(filesystems, opts[name])}
106
+ results.each {|devices| to_unmount += Set.new(devices)}
107
+ to_unmount = to_unmount.to_a
108
+ to_unmount.reverse! if opts[:reverse]
109
+ to_unmount
110
+ end
111
+
112
+ def unmount_many_fs(opts)
113
+ to_unmount = matched_devices(opts)
114
+ if opts[:simulate]
115
+ # TODO: think of a human readable format for -s
116
+ require 'pp'
117
+ pp to_unmount
118
+ elsif opts[:reporting]
119
+ report_results(to_unmount, opts[:reporting])
120
+ else
121
+ unmount_devices(to_unmount, opts[:verbose])
122
+ end
123
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: umount-many
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Hagbard Celine
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-18 00:00:00 +02:00
18
+ default_executable: umount-many
19
+ dependencies: []
20
+
21
+ description: Unmount several devices based on filters
22
+ email: sin3141592@gmail.com
23
+ executables:
24
+ - umount-many
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - TODO
29
+ files:
30
+ - Rakefile
31
+ - TODO
32
+ - VERSION
33
+ - lib/umount-many.rb
34
+ has_rdoc: true
35
+ homepage: http://github.com/hackenporsche/umount-many
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options:
40
+ - --charset=UTF-8
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.3.6
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Unmount several devices based on filters
64
+ test_files: []
65
+