fstab 0.1

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/.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: []