umount-many 0.1.4 → 0.2.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.
- data/README.md +10 -0
- data/Rakefile +1 -2
- data/TODO +1 -2
- data/VERSION +1 -1
- data/bin/umount-many +4 -4
- data/lib/core_ext/hash.rb +16 -0
- data/lib/umount-many.rb +133 -94
- data/pkg/umount-many-0.1.3.gem +0 -0
- data/pkg/umount-many-0.1.4.gem +0 -0
- data/umount-many-0.1.4.gem +0 -0
- data/umount-many.gemspec +17 -12
- metadata +13 -7
data/README.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
umount-many
|
2
|
+
===========
|
3
|
+
|
4
|
+
`umount-many` is a little tool which allows you to unmount several file systems
|
5
|
+
at once by using filters. For example, if you want to unmount every VFAT
|
6
|
+
file system in reversed order, simply enter this at the command line:
|
7
|
+
|
8
|
+
umount-many -t vfat -R
|
9
|
+
|
10
|
+
For a complete list, call `umount-many` with the `-h` option.
|
data/Rakefile
CHANGED
@@ -2,10 +2,9 @@ begin
|
|
2
2
|
require 'jeweler'
|
3
3
|
Jeweler::Tasks.new do |gem|
|
4
4
|
gem.name = "umount-many"
|
5
|
-
gem.executables = "umount-many"
|
6
5
|
gem.summary = "Unmount several devices based on filters"
|
7
6
|
gem.email = "sin3141592@gmail.com"
|
8
|
-
gem.homepage = "
|
7
|
+
gem.homepage = "https://github.com/sin3141592/umount-many"
|
9
8
|
gem.description = gem.summary
|
10
9
|
gem.authors = ["Hagbard Celine"]
|
11
10
|
end
|
data/TODO
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
-
|
2
|
-
- Of course fix the TODO's placed in the code
|
1
|
+
- Of course fix the TODOs placed in the code
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/bin/umount-many
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
|
-
require
|
5
|
-
require File.
|
4
|
+
require "optparse"
|
5
|
+
require File.expand_path("../../lib/umount-many", __FILE__)
|
6
6
|
|
7
7
|
def main
|
8
8
|
opts = Hash.new
|
@@ -54,7 +54,7 @@ def main
|
|
54
54
|
opts[:reverse] = true
|
55
55
|
end
|
56
56
|
end.parse!
|
57
|
-
unmount_many_fs(opts)
|
57
|
+
UmountMany.unmount_many_fs(opts)
|
58
58
|
end
|
59
59
|
|
60
|
-
main
|
60
|
+
main if $0 == __FILE__
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
module HashValuesAt
|
5
|
+
# Works similiar to the +values_at+ method but return
|
6
|
+
# instead of just values an appropriate hash
|
7
|
+
def hash_at(*keys)
|
8
|
+
hash = Hash.new
|
9
|
+
keys.zip(self.values_at(*keys)).each {|k, v| hash[k] = v}
|
10
|
+
hash
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Hash
|
15
|
+
include HashValuesAt
|
16
|
+
end
|
data/lib/umount-many.rb
CHANGED
@@ -4,124 +4,163 @@
|
|
4
4
|
# == umount-many
|
5
5
|
# umount-many allows you to unmount several file systems at once
|
6
6
|
# You can specify several filter types to select the desired file systems
|
7
|
-
# For example:
|
7
|
+
# For example:
|
8
8
|
# +umount-many -t ext4+
|
9
9
|
# This command unmounts every file system that has ext4 as file system type
|
10
10
|
# For a list of all filters use the +-h+ or +--help+ command line option
|
11
11
|
|
12
12
|
require 'optparse'
|
13
13
|
require 'set'
|
14
|
+
require File.expand_path("../core_ext/hash.rb", __FILE__)
|
14
15
|
|
15
|
-
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
module UmountMany
|
17
|
+
# Retrieve a list of all mounted file system. Return an array with hashes
|
18
|
+
# of the following form_
|
19
|
+
# * +:device+: The device file (in +/dev+) from which the file system is
|
20
|
+
# mounted.
|
21
|
+
# * +:mount_point+: The directory to which the file system is mounted
|
22
|
+
# * +:type+: The file system type (e.g. +ext4+).
|
23
|
+
# * +:options+: An array of options such as +rw+ and +nosuid+.
|
24
|
+
def self.parse_file_systems
|
25
|
+
# TODO: Currently calls +mount+ and parses stdout. Not such a good
|
26
|
+
# approach, is it?
|
27
|
+
# TODO: I just can the regex gurantee to work for my box (which is a linux
|
28
|
+
# 2.6.31 with +mount+ from util-linux-ng 2.16)
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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")
|
30
|
+
filesystems = []
|
31
|
+
IO.popen("mount") do |pipe|
|
32
|
+
pipe.each_line do |line|
|
33
|
+
if line =~ /([^\s]+) on ([^\s]+) type ([^\s]+) \((.*)\)/
|
34
|
+
filesystems.push({:device => $1, :mount_point => $2, :type => $3,
|
35
|
+
:options => $4.split(",")})
|
36
|
+
else
|
37
|
+
STDERR.puts("Couldn't parse output from mount. " +
|
38
|
+
"Skipping current line")
|
39
|
+
end
|
40
40
|
end
|
41
41
|
end
|
42
|
+
filesystems
|
42
43
|
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
44
|
|
54
|
-
|
55
|
-
|
56
|
-
|
45
|
+
# Check if a file system is mounted from +device+.
|
46
|
+
def self.filter_by_device(filesystems, device)
|
47
|
+
filesystems.select {|e| e[:device] == device}
|
48
|
+
end
|
57
49
|
|
58
|
-
|
59
|
-
|
60
|
-
|
50
|
+
# Check if a file system is mounted on +mp+.
|
51
|
+
def self.filter_by_mount_point(filesystems, mp)
|
52
|
+
filesystems.select {|e| e[:mount_point] == mp}
|
53
|
+
end
|
61
54
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
filters.push filter if v && !v.empty?
|
55
|
+
# Check if a file system is of the given +type+.
|
56
|
+
def self.filter_by_type(filesystems, type)
|
57
|
+
filesystems.select {|e| e[:type].downcase == type.downcase}
|
66
58
|
end
|
67
|
-
filters.map{|e| [method("filter_by_" + e.to_s), e]}
|
68
|
-
end
|
69
59
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
60
|
+
# Check if all given +options+ are set on a file system
|
61
|
+
def self.filter_by_options(filesystems, option)
|
62
|
+
# TODO: Check whether e[:options] contains *all* set options
|
63
|
+
# (e[:options] & options == options)
|
64
|
+
# Rename option to options
|
65
|
+
filesystems.select {|e| e[:options].include?(option)}
|
75
66
|
end
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
67
|
+
|
68
|
+
# See which filters are set in +opts+ and return an array of the form
|
69
|
+
# <tt>[[filter_by_foo, foo], ...]</tt>. +filter_by_foo+ is a method object
|
70
|
+
# representing the according methods defined in this module. +foo+ is string
|
71
|
+
# naming the filter.
|
72
|
+
def self.collect_filters(opts)
|
73
|
+
filters = []
|
74
|
+
opts.hash_at(:mount_point, :device, :type, :options).each do |filter, v|
|
75
|
+
filters.push filter if v && !v.empty?
|
76
|
+
end
|
77
|
+
filters.map{|e| [method("filter_by_" + e.to_s), e]}
|
84
78
|
end
|
85
|
-
end
|
86
79
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
80
|
+
# Serialize the matched file system in the given +format+. Available
|
81
|
+
# are YAML, JSON and XML (this requires the +xmlsimple+ library). YAML and
|
82
|
+
# JSON use stdlib libraries.
|
83
|
+
def self.report_results(to_unmount, format)
|
84
|
+
unless ["yaml", "json", "xml"].include?(format)
|
85
|
+
puts "Not a supported format for reporting: #{format}"
|
86
|
+
puts "See the help (-h) for a list"
|
87
|
+
exit 2
|
88
|
+
end
|
89
|
+
if format.downcase == "xml"
|
90
|
+
STDERR.puts "WARNING: XML format is experimental."
|
91
|
+
require 'xmlsimple'
|
92
|
+
puts XmlSimple.xml_out(to_unmount)
|
93
|
+
else
|
94
|
+
require format
|
95
|
+
meth = to_unmount.method("to_" + format)
|
96
|
+
puts meth.call
|
92
97
|
end
|
93
|
-
system "umount \"#{device[:device]}\""
|
94
|
-
# Needed because umount takes a bit of time
|
95
|
-
sleep 0.2
|
96
|
-
puts "DONE" if verbose
|
97
98
|
end
|
98
|
-
end
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
100
|
+
# Actually unmount all the given devices. If +verbose+ is +true+, print every
|
101
|
+
# file system before it is unmounted.
|
102
|
+
def self.unmount_devices(devices, verbose)
|
103
|
+
devices.each do |device|
|
104
|
+
if verbose
|
105
|
+
print ("Unmounting #{device[:device]} mounted on " +
|
106
|
+
"#{device[:mount_point]}... ")
|
107
|
+
end
|
108
|
+
system "umount \"#{device[:device]}\""
|
109
|
+
# Needed because umount takes a bit of time
|
110
|
+
sleep 0.2
|
111
|
+
puts "DONE" if verbose
|
112
|
+
end
|
113
|
+
end
|
110
114
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
115
|
+
# Collect the mounted file systems and apply the given filters. Return an
|
116
|
+
# array of hashes. For a description of this data structure see
|
117
|
+
# +parse_file_systems+.
|
118
|
+
def self.matched_devices(opts)
|
119
|
+
filesystems = parse_file_systems
|
120
|
+
filters = collect_filters(opts)
|
121
|
+
to_unmount = Set.new
|
122
|
+
results = filters.map {|meth, name| meth.call(filesystems, opts[name])}
|
123
|
+
results.each {|devices| to_unmount += Set.new(devices)}
|
124
|
+
to_unmount = to_unmount.to_a
|
125
|
+
to_unmount.reverse! if opts[:reverse]
|
126
|
+
to_unmount
|
116
127
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
128
|
+
|
129
|
+
# Main interface to +umount-many+.
|
130
|
+
# +opts+ is a Hash which may consist of the
|
131
|
+
# following keys (+nil+ is the default for all keys)
|
132
|
+
# * +:mount_point+: A path which points to the mounted directory.
|
133
|
+
# * +:device+: A path to the device file (in +/dev+).
|
134
|
+
# * +:type+: The file system (e.g. +ext4+).
|
135
|
+
# * +:options+: An array of set options (e.g. +rw+ or +nosuid+). If all of
|
136
|
+
# these options are set (additional may be set as well), unmount it.
|
137
|
+
# * +:all+: Unmount all of them (merely because we can).
|
138
|
+
# * +:simulate+: If true, do not unmount a single file system, but print
|
139
|
+
# the collected ones to the screen (see +:reporting as well). This is
|
140
|
+
# recommended to check whether the used filters match the correct
|
141
|
+
# file systems.
|
142
|
+
# * +:reporting+: Similar to +:simulate+, but instead of printing in a human
|
143
|
+
# readable format, print in a standardized and easy parsable format.
|
144
|
+
# Currently available are YAML, JSON and XML.
|
145
|
+
# * +:verbose+: If true, print every file system as it is unmount to the
|
146
|
+
# screen
|
147
|
+
# * +:reverse+: Reverse the file systems collection before unmounting. This is
|
148
|
+
# kind of pointless for there is no guarantee for the order of file systems.
|
149
|
+
def self.unmount_many_fs(opts)
|
150
|
+
if opts[:all]
|
151
|
+
to_unmount = parse_file_systems
|
152
|
+
else
|
153
|
+
to_unmount = matched_devices(opts)
|
154
|
+
end
|
155
|
+
if opts[:simulate]
|
156
|
+
to_unmount.each do |device|
|
157
|
+
puts ("#{device[:device]} mounted on #{device[:mount_point]} as " +
|
158
|
+
"#{device[:type]}")
|
159
|
+
end
|
160
|
+
elsif opts[:reporting]
|
161
|
+
report_results(to_unmount, opts[:reporting])
|
162
|
+
else
|
163
|
+
unmount_devices(to_unmount, opts[:verbose])
|
121
164
|
end
|
122
|
-
elsif opts[:reporting]
|
123
|
-
report_results(to_unmount, opts[:reporting])
|
124
|
-
else
|
125
|
-
unmount_devices(to_unmount, opts[:verbose])
|
126
165
|
end
|
127
166
|
end
|
Binary file
|
Binary file
|
Binary file
|
data/umount-many.gemspec
CHANGED
@@ -1,34 +1,39 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{umount-many}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Hagbard Celine"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-23}
|
13
13
|
s.default_executable = %q{umount-many}
|
14
14
|
s.description = %q{Unmount several devices based on filters}
|
15
15
|
s.email = %q{sin3141592@gmail.com}
|
16
16
|
s.executables = ["umount-many"]
|
17
17
|
s.extra_rdoc_files = [
|
18
|
+
"README.md",
|
18
19
|
"TODO"
|
19
20
|
]
|
20
21
|
s.files = [
|
22
|
+
"README.md",
|
21
23
|
"Rakefile",
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
"TODO",
|
25
|
+
"VERSION",
|
26
|
+
"bin/umount-many",
|
27
|
+
"lib/core_ext/hash.rb",
|
28
|
+
"lib/umount-many.rb",
|
29
|
+
"pkg/umount-many-0.1.0.gem",
|
30
|
+
"pkg/umount-many-0.1.1.gem",
|
31
|
+
"pkg/umount-many-0.1.3.gem",
|
32
|
+
"pkg/umount-many-0.1.4.gem",
|
33
|
+
"umount-many-0.1.4.gem",
|
34
|
+
"umount-many.gemspec"
|
29
35
|
]
|
30
|
-
s.homepage = %q{
|
31
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.homepage = %q{https://github.com/sin3141592/umount-many}
|
32
37
|
s.require_paths = ["lib"]
|
33
38
|
s.rubygems_version = %q{1.3.7}
|
34
39
|
s.summary = %q{Unmount several devices based on filters}
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Hagbard Celine
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-01-23 00:00:00 +01:00
|
18
18
|
default_executable: umount-many
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -25,23 +25,29 @@ executables:
|
|
25
25
|
extensions: []
|
26
26
|
|
27
27
|
extra_rdoc_files:
|
28
|
+
- README.md
|
28
29
|
- TODO
|
29
30
|
files:
|
31
|
+
- README.md
|
30
32
|
- Rakefile
|
31
33
|
- TODO
|
32
34
|
- VERSION
|
33
35
|
- bin/umount-many
|
36
|
+
- lib/core_ext/hash.rb
|
34
37
|
- lib/umount-many.rb
|
35
38
|
- pkg/umount-many-0.1.0.gem
|
36
39
|
- pkg/umount-many-0.1.1.gem
|
40
|
+
- pkg/umount-many-0.1.3.gem
|
41
|
+
- pkg/umount-many-0.1.4.gem
|
42
|
+
- umount-many-0.1.4.gem
|
37
43
|
- umount-many.gemspec
|
38
44
|
has_rdoc: true
|
39
|
-
homepage:
|
45
|
+
homepage: https://github.com/sin3141592/umount-many
|
40
46
|
licenses: []
|
41
47
|
|
42
48
|
post_install_message:
|
43
|
-
rdoc_options:
|
44
|
-
|
49
|
+
rdoc_options: []
|
50
|
+
|
45
51
|
require_paths:
|
46
52
|
- lib
|
47
53
|
required_ruby_version: !ruby/object:Gem::Requirement
|