umount-many 0.1.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. 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
+