fstab 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", ">= 0"
10
+ gem "jeweler", "~> 1.8.4"
11
+ gem "rdoc"
12
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 BVox World S.L.U.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # fstab
2
+
3
+ Linux fstab helper library
4
+
5
+ # Usage
6
+
7
+ Adding a new entry to fstab:
8
+
9
+ require 'fstab'
10
+
11
+ # Use default /etc/fstab
12
+ # With safe_mode only valid devices/filesystems will be added to fstab
13
+ # Trying to add non existant device or filesystem will raise an exception
14
+ #
15
+ # :backup => true will create a timestamped fstab backup before saving
16
+ # the changes
17
+ fstab = Fstab.new '/etc/fstab', :safe_mode => true,
18
+ :backup => true, :backup_dir = '/etc/'
19
+
20
+ # Asuming /dev/sda1 has a valid FS
21
+ # The library will use the FS UUID automatically by default even if the block device path
22
+ # was used as an argument. This is usually safer.
23
+ fstab.add_device '/dev/sda1', '/mnt', 'ext4', 'discard,errors=remount-ro', 0, 1
24
+
25
+ # You can use filesystem UUID also
26
+ fstab.add_device '15baeabd-b419-4a69-a306-bc550dc8355f', '/mnt', 'ext4', 'discard,errors=remount-ro', 0, 1
27
+
28
+ # List fstab entries
29
+ fstab.entries.each do |key, val|
30
+ puts val[:label] # FS label, may be nil
31
+ puts val[:uuid] # FS UUID, nil if entry marked as invalid
32
+ puts val[:mount_point]
33
+ puts val[:type]
34
+ puts val[:opts]
35
+ puts val[:dump]
36
+ puts val[:pass]
37
+ puts val[:special] # special FS, i.e. not a block device
38
+ puts val[:line_number] # line number for the FS in fstab
39
+ puts val[:invalid] # the parser marked the entry as invalid
40
+ end
41
+
42
+ Checking if a device is present in /etc/fstab:
43
+
44
+ fstab.has_device? '/dev/sda1' # => true
45
+ # Assuming /dev/sda1 UUID is 15baeabd-b419-4a69-a306-bc550dc8355f
46
+ fstab.has_device? '15baeabd-b419-4a69-a306-bc550dc8355f' # => true
47
+
48
+ Some other helper methods:
49
+
50
+ # Return a hash of 'invalid' entries, i.e. device does not exist or the
51
+ # entry is malformed
52
+ fstab.invalid_entries
53
+ # Automatically remove invalid entries creating a backup file
54
+ fstab.remove_invalid_entries
55
+
56
+ # Get FS UUID
57
+ Fstab.get_uuid '/dev/sda1'
58
+
59
+ # Get FS label, assuming it has one
60
+ # return nil otherwise
61
+ Fstab.get_label '/dev/sda1'
62
+
63
+ # Running the tests
64
+
65
+ rake spec
66
+
67
+ # Copyright
68
+
69
+ Copyright (c) 2012 BVox World S.L.U. See LICENSE.txt for
70
+ further details.
71
+
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ require './lib/fstab.rb'
6
+
7
+ begin
8
+ Bundler.setup(:default, :development)
9
+ rescue Bundler::BundlerError => e
10
+ $stderr.puts e.message
11
+ $stderr.puts "Run `bundle install` to install missing gems"
12
+ exit e.status_code
13
+ end
14
+ require 'rake'
15
+
16
+ require 'jeweler'
17
+ Jeweler::Tasks.new do |gem|
18
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
19
+ gem.version = Fstab::VERSION
20
+ gem.name = "fstab"
21
+ gem.homepage = "http://github.com/bvox/fstab"
22
+ gem.license = "MIT"
23
+ gem.summary = %Q{Linux fstab helper library}
24
+ gem.description = %Q{Linux fstab helper library}
25
+ gem.email = "rubiojr@bvox.net"
26
+ gem.authors = ["Sergio Rubio"]
27
+ # dependencies defined in Gemfile
28
+ end
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ require 'rspec/core/rake_task'
32
+ RSpec::Core::RakeTask.new(:spec)
33
+ task :default => :spec
34
+
35
+ require 'rdoc/task'
36
+ Rake::RDocTask.new do |rdoc|
37
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
38
+
39
+ rdoc.rdoc_dir = 'rdoc'
40
+ rdoc.title = "fstab #{version}"
41
+ rdoc.rdoc_files.include('README*')
42
+ rdoc.rdoc_files.include('lib/**/*.rb')
43
+ end
data/lib/fstab.rb ADDED
@@ -0,0 +1,288 @@
1
+ class Fstab
2
+
3
+ VERSION = "0.1"
4
+
5
+ # if safe_mode true, non existing devices won't be added to fstab.
6
+ # Adding a non existing device to fstab will raise an exception.
7
+ # Trying to add a device without a filesystem will also rise an exception
8
+ #
9
+ def initialize(file = '/etc/fstab', opts = {})
10
+ @file = file
11
+ @contents = File.read file
12
+ @backup = opts[:backup].nil? ? true : opts[:backup]
13
+ @safe_mode = opts[:safe_mode].nil? ? true : opts[:safe_mode]
14
+ @backup_dir = opts[:backup_dir] || '/etc/'
15
+ end
16
+
17
+ def entries
18
+ parse
19
+ end
20
+
21
+ # :label => label or :uuid => uuid or :dev => dev_path
22
+ # :mount_point => mp
23
+ # :type => type
24
+ # :opts => opts
25
+ # :dump => dump
26
+ # :pass => pass
27
+ def add_entry(opts = {})
28
+ raise ArgumentError.new(":dev key is required (fs_spec).") unless opts[:dev]
29
+ dev = opts[:dev].strip.chomp
30
+ uuid = nil
31
+ label = nil
32
+ case dev
33
+ when /\/dev\// # device path
34
+ pdev = dev
35
+ when /^\/\/\w+(\.\w+)*((\/)|\w+|\.)*/ #smbfs/cifs
36
+ when /^(tmpfs|proc|usbfs|devpts|none|sysfs)/ #special FS
37
+ when /^\w+:\/?\w*(\/\w+)*/ # NFS
38
+ when /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i # UUID
39
+ uuid = dev
40
+ else # Asume FS label, rise exception if FS label does not exist
41
+ if File.blockdev?("/dev/disk/by-label/#{dev}")
42
+ label = dev
43
+ else
44
+ raise Exception.new "Unsupported filesystem #{dev}"
45
+ end
46
+ end
47
+
48
+ if opts[:mount_point].nil? or opts[:type].nil? or \
49
+ opts[:opts].nil? or opts[:dump].nil? or opts[:pass].nil?
50
+ raise ArgumentError.new("Missing :mount_point, :type, :opts, :dump or :pass options")
51
+ end
52
+
53
+ if @safe_mode
54
+ if label
55
+ raise ArgumentError.new("Invalid device label #{label}") unless \
56
+ File.blockdev?("/dev/disk/by-label/#{opts[:label]}")
57
+ opts[:uuid] = Fstab.get_uuid_from_label(label)
58
+ elsif uuid
59
+ raise ArgumentError.new("Invalid device UUID #{uuid}") unless \
60
+ File.blockdev?("/dev/disk/by-uuid/#{uuid}")
61
+ opts[:uuid] = uuid
62
+ elsif pdev
63
+ raise ArgumentError.new("Invalid device path #{pdev}") unless \
64
+ File.blockdev?("#{pdev}")
65
+ opts[:uuid] = Fstab.get_uuid(pdev)
66
+ else
67
+ # Asume special device
68
+ special = true
69
+ end
70
+ unless special
71
+ raise ArgumentError.new("Duplicated entry found (safe_mode=on)") if has_device?(dev)
72
+ end
73
+ end
74
+
75
+ backup_fstab
76
+ File.open @file, 'w' do |f|
77
+ f.puts @contents
78
+ f.puts format_entry(dev, opts)
79
+ end
80
+ end
81
+
82
+ def add_fs(dev, mpoint, type, opts, dump = 0, pass = 0)
83
+ o = {}
84
+ o[:dev] = dev
85
+ o[:mount_point] = mpoint
86
+ o[:type] = type
87
+ o[:opts] = opts
88
+ o[:dump] = dump
89
+ o[:pass] = pass
90
+ add_entry o
91
+ end
92
+
93
+ def line_count
94
+ @lcount
95
+ end
96
+
97
+ def parse(reload = true)
98
+ @contents = File.read @file if reload
99
+ raise Exception.new("/sbin/blkid not found") unless File.exist?('/sbin/blkid')
100
+ fslist = {}
101
+ ucount = 0
102
+ @lcount = 0
103
+ @contents.each_line do |l|
104
+ next if l.strip.chomp.empty?
105
+ @lcount += 1
106
+ next if l =~ /\s*#/
107
+ fs, mp, type, opts, dump, pass = l.split
108
+
109
+ # FSTAB(5) states that pass and dump are optional, defaults to 0
110
+ pass = "0" unless pass
111
+ dump = "0" unless dump
112
+ pdev = nil
113
+ label = nil
114
+ uuid = nil
115
+ special = false
116
+ if l =~ /^\s*LABEL=/
117
+ # by LABEL
118
+ label = fs.split("=").last.strip.chomp
119
+ pdev = "/dev/" + File.readlink("/dev/disk/by-label/#{label}").split("/").last rescue "unknown_#{ucount}"
120
+ uuid = Fstab.get_uuid pdev
121
+ elsif l =~ /^\s*UUID=/
122
+ # by UUID
123
+ uuid = fs.split("=").last.strip.chomp
124
+ pdev = "/dev/" + File.readlink("/dev/disk/by-uuid/#{uuid}").split("/").last rescue "unknown_#{ucount}"
125
+ label = Fstab.get_label pdev
126
+ elsif l =~ /^\s*\/dev/
127
+ # by dev path
128
+ pdev = fs
129
+ blkid = `/sbin/blkid #{pdev}`
130
+ label = blkid.match(/LABEL="(.*?)"/)[1] rescue nil
131
+ uuid = blkid.match(/UUID="(.*?)"/)[1] rescue nil
132
+ else
133
+ # FIXME: somewhat risky to assume that everything else
134
+ # can be considered a special device, but validating this
135
+ # is really tricky.
136
+ special = true
137
+ pdev = fs
138
+ end
139
+ # Fstab entries not matching real devices have pdev unknown
140
+ invalid = (l.split.count != 6) # invalid entry if < 6 columns
141
+ if (uuid.nil? and label.nil? and !special) or
142
+ pdev =~ /^unknown_/ or \
143
+ (!File.exist?(pdev) and !special)
144
+ invalid = true
145
+ ucount += 1
146
+ end
147
+
148
+ invalid = true unless (dump =~ /0|1|2/ and pass =~ /0|1|2/)
149
+
150
+ fslist[pdev] = {
151
+ :label => label,
152
+ :uuid => uuid,
153
+ :mount_point => mp,
154
+ :type => type,
155
+ :opts => opts,
156
+ :dump => dump,
157
+ :pass => pass,
158
+ :special => special,
159
+ :line_number => @lcount,
160
+ :invalid => invalid,
161
+ }
162
+ end
163
+ fslist
164
+ end
165
+
166
+ def valid_entries
167
+ Hash[parse.find_all { |k,v| !v[:invalid] }]
168
+ end
169
+
170
+ def auto_header
171
+ @header ||= "#\n" +
172
+ "# This file was autogenerated at #{Time.now.to_s}\n" +
173
+ "#\n"
174
+ end
175
+
176
+ #
177
+ # May rise exception
178
+ #
179
+ def remove_invalid_entries
180
+ return false if invalid_entries.empty?
181
+ backup_fstab
182
+ File.open @file, 'w' do |f|
183
+ f.puts auto_header
184
+ valid_entries.each do |k,v|
185
+ f.puts format_entry(k, v)
186
+ end
187
+ end
188
+ true
189
+ end
190
+
191
+ def invalid_entries
192
+ Hash[parse.find_all { |k,v| v[:invalid] }]
193
+ end
194
+
195
+ #
196
+ # Accepts UUID/LABEL/dev
197
+ #
198
+ def find_device(dev)
199
+ # get canonical device_name
200
+ begin
201
+ dev = Fstab.get_blockdev(dev)
202
+ parse.each do |k, v|
203
+ return { k => v } if k == dev
204
+ end
205
+ rescue
206
+ end
207
+ nil
208
+ end
209
+
210
+ def has_device?(dev)
211
+ !find_device(dev).nil?
212
+ end
213
+
214
+ # returns
215
+ # {
216
+ # :uuid => UUID,
217
+ # :label => LABEL,
218
+ # :fstype => FSTYPE,
219
+ # :dev => DEVICE
220
+ # }
221
+ #
222
+ # All the attributes except dev may be nil at any given time since
223
+ # device may not have a valid filesystem or label.
224
+ def self.get_blkdev_fs_attrs(dev)
225
+ raise ArgumentError.new("Invalid device path") unless File.blockdev?(dev)
226
+ blkid = `/sbin/blkid #{dev}`
227
+ attrs = {}
228
+ attrs[:uuid] = blkid.match(/UUID="(.*?)"/)[1] rescue nil
229
+ attrs[:label] = blkid.match(/LABEL="(.*?)"/)[1] rescue nil
230
+ attrs[:fstype] = blkid.match(/TYPE="(.*?)"/)[1] rescue nil
231
+ attrs[:dev] = blkid.match(/\/dev\/(.*):/)[1] rescue nil
232
+ attrs
233
+ end
234
+
235
+ #
236
+ # Get block device from UUID/Label
237
+ def self.get_blockdev(id)
238
+ if File.blockdev?(id) and !File.symlink?(id)
239
+ return id
240
+ end
241
+ path = nil
242
+ # Try to get blockdev from UUID first, then label
243
+ begin
244
+ path = File.readlink("/dev/disk/by-uuid/#{id}")
245
+ rescue
246
+ path = File.readlink("/dev/disk/by-label/#{id}")
247
+ end
248
+ "/dev/#{path.split('/').last}"
249
+ end
250
+
251
+ def self.get_uuid(dev)
252
+ #`/sbin/blkid #{dev}`.match(/UUID="(.*?)"/)[1] rescue nil
253
+ Fstab.get_blkdev_fs_attrs(dev)[:uuid]
254
+ end
255
+
256
+ def self.get_uuid_from_label(label)
257
+ Fstab.get_blkdev_fs_attrs("/dev/disk/by-label/#{label}")[:uuid]
258
+ end
259
+
260
+ def self.get_label(dev)
261
+ Fstab.get_blkdev_fs_attrs(dev)[:label]
262
+ end
263
+
264
+ private
265
+ def format_entry(dev, values)
266
+ if values[:special]
267
+ "#{dev} #{values[:mount_point]} #{values[:type]} " +
268
+ "#{values[:opts]} #{values[:dump]} #{values[:pass]}"
269
+ else
270
+ if values[:uuid]
271
+ "UUID=#{values[:uuid]} #{values[:mount_point]} #{values[:type]} " +
272
+ "#{values[:opts]} #{values[:dump]} #{values[:pass]}"
273
+ else
274
+ "#{dev} #{values[:mount_point]} #{values[:type]} " +
275
+ "#{values[:opts]} #{values[:dump]} #{values[:pass]}"
276
+ end
277
+ end
278
+ end
279
+
280
+ def backup_fstab
281
+ return unless @backup
282
+ File.open("#{@backup_dir}/fstab.#{Time.now.to_f}.bak", 'w') do |f|
283
+ f.puts @contents
284
+ end
285
+ end
286
+
287
+ end
288
+
@@ -0,0 +1,309 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fstab do
4
+
5
+ before :each do
6
+ @fake_fstab = "/tmp/fstab.#{Time.now.to_f}.fake"
7
+ File.open @fake_fstab, 'w' do |f|
8
+ f.puts ""
9
+ end
10
+
11
+ @real_fstab = "/tmp/fstab.#{Time.now.to_f}.real"
12
+ File.open @real_fstab, 'w' do |f|
13
+ f.puts File.read('/etc/fstab')
14
+ end
15
+ end
16
+
17
+ after :each do
18
+ File.delete @fake_fstab
19
+ File.delete @real_fstab
20
+ Dir["/tmp/fstab*.bak"].each do |f|
21
+ File.delete f
22
+ end
23
+ end
24
+
25
+ describe "#new" do
26
+ it "accepts two optional arguments" do
27
+ h = Fstab.new '/etc/fstab', {}
28
+ end
29
+
30
+ it "raises exception unless opts is not Hash" do
31
+ lambda { Fstab.new(@real_fstab, false) }.should raise_error NoMethodError
32
+ end
33
+
34
+ it "accepts no arguments" do
35
+ h = Fstab.new
36
+ end
37
+
38
+ it "raises exception if file does not exist" do
39
+ lambda { Fstab.new('/tmp/lkjsdfouwoiue') }.should raise_exception(Errno::ENOENT)
40
+ end
41
+
42
+ it "reads custom #{@fake_fstab}" do
43
+ h = Fstab.new @fake_fstab
44
+ h.instance_variable_get(:@contents).strip.chomp.should be_empty
45
+ end
46
+
47
+ it "has backups enabled by default" do
48
+ h = Fstab.new @fake_fstab
49
+ h.instance_variable_get(:@backup).should be_true
50
+ end
51
+
52
+ end
53
+
54
+ describe "#parse" do
55
+ it "should count lines" do
56
+ count = File.read('/etc/fstab').lines.count
57
+ f = Fstab.new(@real_fstab); f.parse
58
+ f.line_count.should be count
59
+ end
60
+
61
+ it "should return empty Hash if empty" do
62
+ Fstab.new(@fake_fstab).parse.should be_empty
63
+ end
64
+ it "should have 1 special FS" do
65
+ File.open @fake_fstab, 'w+' do |f|
66
+ f.puts 'proc /proc proc nodev,noexec,nosuid 0 0'
67
+ f.flush
68
+ fstab = Fstab.new @fake_fstab
69
+ devs = fstab.parse
70
+ devs.count.should == 1
71
+ # d[:special] == true
72
+ devs.first.last[:special].should == true
73
+ end
74
+ end
75
+
76
+ it "should detect special filesystems as valid" do
77
+ File.open @fake_fstab, 'w+' do |f|
78
+ f.puts 'proc /proc proc nodev,noexec,nosuid 0 0'
79
+ f.flush
80
+ fstab = Fstab.new @fake_fstab
81
+ devs = fstab.parse
82
+ devs.count.should == 1
83
+ devs.first.last[:invalid].should == false
84
+ end
85
+ end
86
+
87
+ it "should detect invalid dump/pass columns" do
88
+ File.open @fake_fstab, 'w+' do |f|
89
+ f.puts 'proc /proc proc nodev,noexec,nosuid a b'
90
+ f.flush
91
+ fstab = Fstab.new @fake_fstab
92
+ devs = fstab.parse
93
+ devs.count.should == 1
94
+ devs.first.last[:invalid].should == true
95
+ end
96
+ end
97
+
98
+ it "should detect invalid filesystems" do
99
+ File.open @fake_fstab, 'w+' do |f|
100
+ f.puts '/dev/foobar /tmp/bar xfs defaults 0 0'
101
+ f.flush
102
+ fstab = Fstab.new @fake_fstab
103
+ devs = fstab.parse
104
+ devs.count.should == 1
105
+ devs.first.last[:invalid].should == true
106
+ f.puts 'weird_entry foo bar'
107
+ f.flush
108
+ devs = fstab.parse
109
+ devs.count.should == 2
110
+ devs.each do |k,v|
111
+ v[:invalid].should == true
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ describe "#add_fs" do
118
+ it "should raise an exception adding a non existing device" do
119
+ f = Fstab.new(@real_fstab)
120
+ lambda {f.add_fs '/dev/fff', '/foo/bar', 'xfs', 'defaults'}.should \
121
+ raise_error /Invalid device path/
122
+ end
123
+ it "should raise an exception adding a non existing dev label" do
124
+ f = Fstab.new(@real_fstab)
125
+ lambda {f.add_fs 'my-foo-fs', '/foo/bar', 'xfs', 'defaults'}.should \
126
+ raise_error /Unsupported filesystem/
127
+ end
128
+ it "should raise an exception adding a non existing dev uuid" do
129
+ f = Fstab.new(@real_fstab)
130
+ lambda {f.add_fs 'ca803c3f-32e6-423e-994a-52f648a0321d', '/foo/bar', 'xfs', 'defaults'}.should \
131
+ raise_error /Invalid device UUID/
132
+ end
133
+ it "should raise an exception adding a non existing dev label" do
134
+ f = Fstab.new(@real_fstab)
135
+ lambda {f.add_fs 'my-foo-fs', '/foo/bar', 'xfs', 'defaults'}.should \
136
+ raise_error /Unsupported filesystem/
137
+ end
138
+
139
+ it "should add invalid device when safe_mode=false" do
140
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup_dir => '/tmp')
141
+ f.add_fs '/dev/foo_dev', '/foo/bar', 'xfs', 'defaults'
142
+ f.invalid_entries.count.should == 1
143
+ end
144
+
145
+ it "should create a backup when backup=true (default)" do
146
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup_dir => '/tmp')
147
+ f.add_fs '/dev/foo_dev', '/foo/bar', 'xfs', 'defaults'
148
+ Dir["/tmp/fstab*.bak"].count.should == 1
149
+ end
150
+
151
+ it "should NOT create a backup when backup=false" do
152
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
153
+ f.add_fs '/dev/foo_dev', '/foo/bar', 'xfs', 'defaults'
154
+ Dir["/tmp/fstab*.bak"].count.should == 0
155
+ end
156
+
157
+ it "should add a valid special FS entry" do
158
+ f = Fstab.new(@fake_fstab, :backup => false, :backup_dir => '/tmp')
159
+ prev_count = f.parse.count
160
+ f.add_fs 'tmpfs', '/foo/bar', 'tmpfs', 'size=1024', '0', '0'
161
+ f.parse.count.should == prev_count + 1
162
+ File.read(@fake_fstab).should match /^tmpfs/m
163
+ end
164
+
165
+ it "should add a FS UUID" do
166
+ f = Fstab.new(@fake_fstab, :safe_mode => true, :backup => false, :backup_dir => '/tmp')
167
+ pdev, uuid, label, type = get_first_blkid
168
+ f.add_fs uuid, '/foo/bar', type, 'defaults', '0', '0'
169
+ File.read(@fake_fstab).should match /^UUID=#{uuid}/m
170
+ end
171
+
172
+ it "should add a FS UUID when using a blockdev" do
173
+ f = Fstab.new(@fake_fstab, :safe_mode => true, :backup => false, :backup_dir => '/tmp')
174
+ pdev, uuid, label, type = get_first_blkid
175
+ f.add_fs pdev, '/foo/bar', type, 'defaults', '0', '0'
176
+ File.read(@fake_fstab).should match /^UUID=#{uuid}/m
177
+ end
178
+
179
+ it "should raise error when adding duplicated entry and safe_mode=true" do
180
+ f = Fstab.new(@fake_fstab, :backup => false, :backup_dir => '/tmp')
181
+ pdev, uuid, label, type = get_first_blkid
182
+ f.add_fs uuid, '/foo/bar', type, 'defaults', '0', '0'
183
+ lambda {f.add_fs uuid, '/foo/bar', type, 'defaults', '0', '0'}.should raise_error /Duplicated entry found/
184
+ lambda {f.add_fs pdev, '/foo/bar', type, 'defaults', '0', '0'}.should raise_error /Duplicated entry found/
185
+ end
186
+ end
187
+
188
+ describe "#add_entry" do
189
+ it "should raise an exception when missing mount_point/type/opts,dump,pass" do
190
+ f = Fstab.new(@real_fstab)
191
+ opts = {
192
+ :dev => '/dev/sda',
193
+ :mount_point => '/foo/bar',
194
+ :type => 'xfs',
195
+ :opts => 'defaults',
196
+ :dump => 0,
197
+ :pass => 0
198
+ }
199
+ [:mount_point, :type, :opts, :dump, :pass].each do |s|
200
+ dup_opts = opts.dup; dup_opts.delete s
201
+ lambda {f.add_entry dup_opts}.should \
202
+ raise_error /Missing :mount_point, :type, :opts/
203
+ end
204
+ end
205
+
206
+ it "should raise and exception when dev/uuid/label nil" do
207
+ f = Fstab.new(@real_fstab)
208
+ opts = {
209
+ :mount_point => '/foo/bar',
210
+ :type => 'xfs',
211
+ :opts => 'defaults',
212
+ :dump => 0,
213
+ :pass => 0
214
+ }
215
+ lambda {f.add_entry opts}.should \
216
+ raise_error /:dev key is required/
217
+ end
218
+ end
219
+
220
+ describe "#invalid_entries" do
221
+ it "should return one entry" do
222
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
223
+ f.add_fs '/dev/foo_dev', '/foo/bar', 'xfs', 'defaults'
224
+ f.invalid_entries.count.should == 1
225
+ end
226
+ end
227
+
228
+ describe "#valid_entries" do
229
+ it "should only return valid entries" do
230
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
231
+ f.add_fs '/dev/foo_dev', '/foo/bar', 'xfs', 'defaults'
232
+ lcount = File.read(@real_fstab).lines.find_all do |l|
233
+ (l.strip.chomp !~ /^#/) and !l.strip.chomp.empty?
234
+ end.count
235
+ f.valid_entries.count.should == lcount - 1
236
+ end
237
+
238
+ it "should match the number of devices" do
239
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
240
+ f.valid_entries.count.should == f.parse.count
241
+ end
242
+ end
243
+
244
+ describe "#remove_invalid_entries" do
245
+ it "should remove 1 entry" do
246
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
247
+ prev_count = f.parse.count
248
+ f.add_fs '/dev/foo_dev', '/foo/bar', 'xfs', 'defaults'
249
+ f.remove_invalid_entries.should == true
250
+ end
251
+ end
252
+
253
+ describe "#find_device" do
254
+ it "should return nil if device not found" do
255
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
256
+ f.find_device('/alksjdflkjsd').should be_nil
257
+ end
258
+
259
+ it "should return a valid device if device is defined" do
260
+ pdev, uuid, label, type = get_first_blkid
261
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
262
+ f.add_fs pdev, '/foo/bar', type, 'defaults'
263
+ f.find_device(pdev).should be_a Hash
264
+ k, dev = f.find_device(pdev).first
265
+ dev.should_not be_nil
266
+ k.should match pdev
267
+ dev[:mount_point].should match '/foo/bar'
268
+ end
269
+ end
270
+
271
+ describe "#has_device?" do
272
+ it "should return true if device is defined" do
273
+ pdev, uuid, label, type = get_first_blkid
274
+ f = Fstab.new(@fake_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
275
+ f.add_fs pdev, '/foo/bar', type, 'defaults'
276
+ f.has_device?(pdev).should == true
277
+ f.has_device?(uuid).should == true
278
+ end
279
+ it "should return true if device is defined" do
280
+ pdev, uuid, label, type = get_first_blkid
281
+ f = Fstab.new(@real_fstab, :safe_mode => false, :backup => false, :backup_dir => '/tmp')
282
+ f.add_fs pdev, '/foo/bar', type, 'defaults'
283
+ f.has_device?(pdev).should == true
284
+ end
285
+ end
286
+
287
+ describe "get_label" do
288
+ it "should raise exception for an invalid device" do
289
+ lambda {Fstab.get_label('/akjsdfljaslkdj')}.should raise_error ArgumentError
290
+ end
291
+
292
+ it "should return a valid LABEL for device with a labeled FS" do
293
+ pdev, uuid, label, type = get_first_blkid
294
+ Fstab.get_label(pdev).should be_nil
295
+ Fstab.get_uuid(pdev).should match uuid
296
+ if label.nil?
297
+ Fstab.get_label(pdev).should be_nil
298
+ end
299
+ end
300
+ end
301
+
302
+ describe "get_uuid" do
303
+ it "should return a valid UUID for device with a FS" do
304
+ pdev, uuid, label, type = get_first_blkid
305
+ Fstab.get_uuid(pdev).should match uuid
306
+ end
307
+ end
308
+
309
+ end
@@ -0,0 +1,11 @@
1
+ $: << File.join(File.dirname(__FILE__), '../lib')
2
+ require 'fstab'
3
+
4
+ def get_first_blkid
5
+ blkid = `/sbin/blkid`.lines.first
6
+ uuid = blkid.match(/UUID="(.*?)"\s+/)[1]
7
+ label = blkid.match(/LABEL="(.*?)"\s+/)[1] rescue nil
8
+ type = blkid.match(/TYPE="(.*?)"\s+/)[1]
9
+ pdev = blkid.match(/(\/dev\/.*?):/)[1]
10
+ return pdev, uuid, label, type
11
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fstab
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sergio Rubio
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: jeweler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.8.4
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.8.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: rdoc
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Linux fstab helper library
63
+ email: rubiojr@bvox.net
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files:
67
+ - LICENSE.txt
68
+ - README.md
69
+ files:
70
+ - .document
71
+ - Gemfile
72
+ - LICENSE.txt
73
+ - README.md
74
+ - Rakefile
75
+ - lib/fstab.rb
76
+ - spec/fstab_helper_spec.rb
77
+ - spec/spec_helper.rb
78
+ homepage: http://github.com/bvox/fstab
79
+ licenses:
80
+ - MIT
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ segments:
92
+ - 0
93
+ hash: 866801040596206319
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 1.8.24
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Linux fstab helper library
106
+ test_files: []