rfuse 1.0.5 → 1.1.0.RC0

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/lib/rfuse.rb CHANGED
@@ -6,6 +6,7 @@ require 'rfuse/compat'
6
6
  # Ruby FUSE (Filesystem in USErspace) binding
7
7
  module RFuse
8
8
 
9
+ # @private
9
10
  # Used by listxattr
10
11
  def self.packxattr(xattrs)
11
12
  case xattrs
@@ -15,7 +16,7 @@ module RFuse
15
16
  #assume already \0 separated list of keys
16
17
  xattrs
17
18
  else
18
- raise RFuse::Error, ":listxattr must return Array or String, got #{xattrs.inspect}"
19
+ raise Error, ":listxattr must return Array or String, got #{xattrs.inspect}"
19
20
  end
20
21
  end
21
22
 
@@ -29,54 +30,55 @@ module RFuse
29
30
  # from argv, ie so argv is a clean set of options that can be passed
30
31
  # to {RFuse::Fuse} or {RFuse::FuseDelegator}
31
32
  #
32
- #
33
- # @return [Hash{Symbol => String,Boolean}]
33
+ #
34
+ # @return [Hash<Symbol,String|Boolean>]
34
35
  # the extracted options
35
36
  #
36
37
  # @since 1.0.3
37
- #
38
+ #
38
39
  # Fuse itself will normalise arguments
39
40
  #
40
- # mount -t fuse </path/to/fs>#<device> mountpoint [options...]
41
- # mount.fuse </path/to/fs>#<device> mountpoint [options...]
41
+ # mount -t fuse </path/to/fs.rb>#<device> mountpoint [options...]
42
+ # mount.fuse </path/to/fs.rb>#<device> mountpoint [options...]
42
43
  #
43
- # both result in a call to /path/to/fs with arguments...
44
+ # both result in the following command execution
44
45
  #
45
- # [device] mountpoint [-h] [-o [opt,optkey=value,...]]
46
+ # /path/to/fs.rb [device] mountpoint [-h] [-d] [-o [opt,optkey=value,...]]
46
47
  #
47
48
  # which this method will parse into a Hash with the following special keys
48
49
  #
49
- # :device - the optional mount device, removed from argv if present
50
- # :mountpoint - required mountpoint
51
- # :help - true if -h was supplied
50
+ # * `:device` - the optional mount device, removed from argv if present
51
+ # * `:mountpoint` - required mountpoint
52
+ # * `:help` - if -h was supplied - will print help text (and not mount the filesystem!)
53
+ # * `:debug` - if -d (or -o debug) was supplied - will print debug output from the underlying FUSE library
52
54
  #
53
55
  # and any other supplied options.
54
56
  #
55
57
  # @example
56
58
  # ARGV = [ "some/device", "/mnt/point", "-h", "-o", "debug,myfs=aValue" ]
57
59
  # options = RFuse.parse_options(ARGV,:myfs)
58
- #
59
- # # options ==
60
+ #
61
+ # # options ==
60
62
  # { :device => "some/device",
61
63
  # :mountpoint => "/mnt/point",
62
64
  # :help => true,
63
65
  # :debug => true,
64
66
  # :myfs => "aValue"
65
67
  # }
66
- # # and ARGV ==
68
+ # # and ARGV ==
67
69
  # [ "/mnt/point","-h","-o","debug" ]
68
70
  #
69
71
  # fs = create_filesystem(options)
70
72
  # fuse = RFuse::FuseDelegator.new(fs,*ARGV)
71
- #
73
+ #
72
74
  def self.parse_options(argv,*local_opts)
73
75
  result = Hash.new(nil)
74
-
75
- first_opt_index = (argv.find_index() { |opt| opt =~ /-.*/ } || argv.length )
76
+
77
+ first_opt_index = (argv.find_index() { |opt| opt =~ /-.*/ } || argv.length )
76
78
 
77
79
  result[:device] = argv.shift if first_opt_index > 1
78
80
  result[:mountpoint] = argv[0] if argv.length > 0
79
-
81
+
80
82
  if argv.include?("-h")
81
83
  result[:help] = true
82
84
  end
@@ -90,7 +92,7 @@ module RFuse
90
92
  if opt_index > 1 && opt_index < argv.length
91
93
  options = argv[opt_index].split(",")
92
94
 
93
- options.delete_if() do |opt|
95
+ options.delete_if() do |opt|
94
96
  opt.strip!
95
97
 
96
98
  opt,value = opt.split("=",2)
@@ -118,16 +120,188 @@ module RFuse
118
120
  # @param [String] exec the executable
119
121
  # @return [String] the usage string
120
122
  def self.usage(device=nil,exec=File.basename($0))
121
- "Usage:\n\t #{exec} #{device} mountpoint [-h] [-o [opt,optkey=value,...]]\n"
123
+ "Usage:\n #{exec} #{device} mountpoint [-h] [-d] [-o [opt,optkey=value,...]]\n"
122
124
  end
123
125
 
126
+ # Convenience method to launch a fuse filesystem, with nice usage messages and default signal traps
127
+ #
128
+ # @param [Array<String>] argv command line arguments
129
+ # @param [Array<Symbol>] extra_options list of additional options
130
+ # @param [String] extra_options_usage describing additional option usage
131
+ # @param [String] device a description of the device field
132
+ # @param [String] exec the executable file
133
+ #
134
+ # @yieldparam [Hash<Symbol,String>] options See {.parse_options}
135
+ # @yieldparam [Array<String>] argv Cleaned argv See {.parse_options}
136
+ #
137
+ # @yieldreturn [Class<Fuse>]
138
+ # a subclass of {Fuse} that implements your filesystem. Will receive `.new(*extra_options,*argv)`
139
+ #
140
+ # @yieldreturn [Class]
141
+ # a class that implements {FuseDelegator::FUSE_METHODS}. Will receive `.new(*extra_options)`
142
+ # and the resulting instance sent with `*argv` to {FuseDelegator}
143
+ #
144
+ # @yieldreturn [Fuse]
145
+ # Your initialised (and therefore already mounted) filesystem
146
+ #
147
+ # @yieldreturn [Object]
148
+ # An object that implements the {Fuse} methods, to be passed with `*argv` to {FuseDelegator}
149
+ #
150
+ # @yieldreturn [Error]
151
+ # raise {Error} with appropriate message for invalid options
152
+ #
153
+ # @since 1.1.0
154
+ #
155
+ # @example
156
+ #
157
+ # class MyFuse < Fuse
158
+ # def initialize(myfs,*argv)
159
+ # @myfs = myfs # my filesystem local option value
160
+ # super(*argv)
161
+ # end
162
+ # # ... implementations for filesystem methods ...
163
+ # end
164
+ #
165
+ # class MyFSClass # not a subclass of Fuse, FuseDelegator used
166
+ # def initialize(myfs)
167
+ # @myfs = myfs # my filesystem local option value
168
+ # end
169
+ # # ...
170
+ # end
171
+ #
172
+ # MY_OPTIONS = [ :myfs ]
173
+ # OPTION_USAGE = " -o myfs=VAL how to use the myfs option"
174
+ # DEVICE_USAGE = "how to use device arg"
175
+ #
176
+ # # Normally from the command line...
177
+ # ARGV = [ "some/device", "/mnt/point", "-h", "-o", "debug,myfs=aValue" ]
178
+ #
179
+ # RFuse.main(ARGV, MY_OPTIONS, OPTION_USAGE, DEVICE_USAGE, $0) do |options, argv|
180
+ #
181
+ # # options ==
182
+ # { :device => "some/device",
183
+ # :mountpoint => "/mnt/point",
184
+ # :help => true,
185
+ # :debug => true,
186
+ # :myfs => "aValue"
187
+ # }
188
+ #
189
+ # # ... validate options...
190
+ # raise RFuse::Error, "Bad option" unless options[:myfs]
191
+ #
192
+ # # return the filesystem class to be initialised by RFuse
193
+ # MyFuse
194
+ # # or
195
+ # MyFSClass
196
+ #
197
+ # # OR take full control over initialisation yourself and return the object
198
+ # MyFuse.new(options[:myfs],*argv)
199
+ # # or
200
+ # MyFSClass.new(options[:myfs])
201
+ #
202
+ # end
203
+ #
204
+ def self.main(argv=ARGV,extra_options=[],extra_options_usage=nil,device=nil,exec=File.basename($0))
205
+
206
+ options = parse_options(argv,*extra_options)
207
+
208
+ unless options[:mountpoint]
209
+ $stderr.puts "rfuse: failed, no mountpoint provided"
210
+ puts usage(device,exec)
211
+ return nil
212
+ end
213
+
214
+ if options[:help]
215
+ puts usage(device,exec)
216
+ # TODO: In Fuse 3.0 this looks like it will move to $stdout
217
+ help_io = STDERR
218
+ help_io.puts "Fuse options: (#{FUSE_MAJOR_VERSION}.#{FUSE_MINOR_VERSION})"
219
+ help_io.puts " -h help - print this help output"
220
+ help_io.puts " -d |-o debug enable internal FUSE debug output"
221
+ help_io.puts ""
222
+ help_io.flush()
223
+
224
+ # Cause Fuse kernel Options to print, but don't actually start a filesystem
225
+ Fuse.new(*argv)
226
+
227
+ if extra_options_usage
228
+ help_io.puts "Filesystem options:"
229
+ help_io.puts extra_options_usage
230
+ end
231
+
232
+ return nil
233
+ end
234
+
235
+ begin
236
+ fs = yield options,argv
237
+
238
+ raise Error, "no filesystem provided" unless fs
239
+
240
+ fuse = create(fs,argv,options,extra_options)
241
+
242
+ raise Error, "filesystem #{fs} not mounted" unless fuse && fuse.mounted?
243
+
244
+ fuse.run
245
+ rescue Error => fuse_ex
246
+ # These errors are produced generally because the user passed bad arguments etc..
247
+ puts usage(device,exec) unless options[:help]
248
+ $stderr.puts "rfuse failed: #{fuse_ex.message}"
249
+ return nil
250
+ rescue => ex
251
+ # These are other errors related the yield block
252
+ $stderr.puts ex.message
253
+ $stderr.puts ex.backtrace.join("\n")
254
+ end
255
+
256
+ end
257
+
258
+
259
+ # @private
260
+ # Helper to create a {Fuse} from variety of #{.main} yield results
261
+ def self.create(fs, argv=[], options = {}, extra_options = [])
262
+ if fs.kind_of?(Fuse)
263
+ fs
264
+ elsif fs.is_a?(Class)
265
+ extra_option_values = extra_options.map { |o| options[o] }
266
+ if Fuse > fs
267
+ fs.new(*extra_option_values,*argv)
268
+ else
269
+ delegate = fs.new(*extra_option_values)
270
+ FuseDelegator.new(delegate,*argv)
271
+ end
272
+ elsif fs
273
+ FuseDelegator.new(fs,*argv)
274
+ end
275
+ end
276
+
277
+ public
278
+
124
279
  class Fuse
125
280
 
281
+ # Convenience method to run a mounted filesystem to completion.
282
+ #
283
+ # @param [Array<String|Integer>] signals list of signals to handle.
284
+ # Default is all available signals. See {#trap_signals}
285
+ #
286
+ # @return [void]
287
+ # @since 1.1.0
288
+ # @see RFuse.main
289
+ def run(signals=Signal.list.keys)
290
+ if mounted?
291
+ begin
292
+ traps = trap_signals(*signals)
293
+ self.loop()
294
+ ensure
295
+ traps.each { |t| Signal.trap(t,"DEFAULT") }
296
+ unmount()
297
+ end
298
+ end
299
+ end
300
+
126
301
  # Main processing loop
127
302
  #
128
303
  # Use {#exit} to stop processing (or externally call fusermount -u)
129
304
  #
130
- #
131
305
  # Other ruby threads can continue while loop is running, however
132
306
  # no thread can operate on the filesystem itself (ie with File or Dir methods)
133
307
  #
@@ -143,8 +317,12 @@ module RFuse
143
317
 
144
318
  if ready.include?(@pr)
145
319
 
146
- @pr.getc
147
- @running = false
320
+ signo = @pr.read_nonblock(1).unpack("c")[0]
321
+
322
+ # Signal.signame exist in Ruby 2, but returns horrible errors for non-signals in 2.1.0
323
+ if (signame = Signal.list.invert[signo])
324
+ call_sigmethod(sigmethod(signame))
325
+ end
148
326
 
149
327
  elsif errors.include?(@fuse_io)
150
328
 
@@ -159,28 +337,85 @@ module RFuse
159
337
  @running = false
160
338
  end
161
339
  end
162
- rescue Interrupt
340
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
163
341
  #oh well...
164
342
  end
165
343
  end
166
344
  end
167
345
 
168
346
  # Stop processing {#loop}
169
- # eg called from Signal handlers, or some other monitoring thread
347
+ # eg called from signal handlers, or some other monitoring thread
170
348
  def exit
171
- @pw.putc(0)
349
+ @running = false
350
+ send_signal(-1)
351
+ end
352
+
353
+ # Set traps
354
+ #
355
+ # The filesystem supports a signal by providing a `sig<name>` method. eg {#sigint}
356
+ #
357
+ # The fuse {#loop} is notified of the signal via the self-pipe trick, and calls the corresponding
358
+ # `sig<name>` method, after any current filesystem operation completes.
359
+ #
360
+ # This method will not override traps that have previously been set to something other than "DEFAULT"
361
+ #
362
+ # Note: {Fuse} itself provides {#sigterm} and {#sigint}.
363
+ #
364
+ # @param [Array<String>] signames
365
+ # List of signal names to set traps for, if the filesystem has methods to handle them.
366
+ # Use `Signal.list.keys` to try all available signals.
367
+ #
368
+ # @return [Array<String>] List of signal names that traps have been set for.
369
+ #
370
+ # @since 1.1.0
371
+ #
372
+ # @example
373
+ # class MyFS < Fuse
374
+ # def sighup()
375
+ # # do something on HUP signal
376
+ # end
377
+ # end
378
+ #
379
+ # fuse = MyFS.new(*args)
380
+ #
381
+ # if fuse.mounted?
382
+ # # Below will result in (effectively) Signal.trap("HUP") { fuse.sighup() }
383
+ # fuse.trap_signals("HUP","USR1") # ==> ["HUP"]
384
+ # fuse.loop()
385
+ # end
386
+ #
387
+ def trap_signals(*signames)
388
+ signames.map { |n| n.to_s.upcase }.map { |n| n.start_with?("SIG") ? n[3..-1] : n }.select do |signame|
389
+ next false unless respond_sigmethod?(sigmethod(signame)) && signo = Signal.list[signame]
390
+
391
+ next true if (prev = Signal.trap(signo) { |signo| send_signal(signo) }) == "DEFAULT"
392
+
393
+ Signal.trap(signo,prev)
394
+ false
395
+ end
396
+ end
397
+
398
+ # Default signal handler to exit on TERM/INT
399
+ # @return [void]
400
+ # @see #trap_signals
401
+ def sigterm
402
+ @running = false
172
403
  end
404
+ alias :sigint :sigterm
173
405
 
174
406
  private
175
407
 
176
408
  # Called by the C iniitialize
177
409
  # afer the filesystem has been mounted successfully
178
410
  def ruby_initialize
411
+ @running = false
412
+
413
+ # Self-pipe for handling signals and exit
179
414
  @pr,@pw = IO.pipe()
180
415
 
181
416
  # The FD was created by FUSE so we don't want
182
417
  # ruby to do anything with it during GC
183
- @fuse_io = IO.for_fd(fd(),"r",:autoclose => false)
418
+ @fuse_io = IO.for_fd(fd(),"r",:autoclose => false)
184
419
  end
185
420
 
186
421
  # Called by C unmount before doing all the FUSE stuff
@@ -194,6 +429,22 @@ module RFuse
194
429
  # we can do
195
430
  @fuse_io.close() if @fuse_io && !@fuse_io.closed? && @fuse_io.autoclose?
196
431
  end
432
+
433
+ def call_sigmethod(sigmethod)
434
+ send(sigmethod)
435
+ end
436
+
437
+ def respond_sigmethod?(sigmethod)
438
+ respond_to?(sigmethod)
439
+ end
440
+
441
+ def sigmethod(signame)
442
+ "sig#{signame.downcase}".to_sym
443
+ end
444
+
445
+ def send_signal(signo)
446
+ @pw.write([signo].pack("c")) unless !@pw || @pw.closed?
447
+ end
197
448
  end
198
449
 
199
450
  #This class is useful to make your filesystem implementation
@@ -203,7 +454,7 @@ module RFuse
203
454
 
204
455
  # Available fuse methods -see http://fuse.sourceforge.net/doxygen/structfuse__operations.html
205
456
  # Note :getdir and :utime are deprecated
206
- # :ioctl, :poll are not implemented in the C extension
457
+ # :ioctl, :poll are not implemented in the C extension
207
458
  FUSE_METHODS = [ :getattr, :readlink, :getdir, :mknod, :mkdir,
208
459
  :unlink, :rmdir, :symlink, :rename, :link,
209
460
  :chmod, :chown, :truncate, :utime, :open,
@@ -216,32 +467,69 @@ module RFuse
216
467
  # @param [Object] fuse_object your filesystem object that responds to fuse methods
217
468
  # @param [String] mountpoint existing directory where the filesystem will be mounted
218
469
  # @param [String...] options fuse mount options (use "-h" to see a list)
219
- #
470
+ #
220
471
  # Create and mount a filesystem
221
472
  #
222
- # If ruby debug is enabled then each call to fuse_object will be represented on $stderr
223
473
  def initialize(fuse_object,mountpoint,*options)
224
474
  @fuse_delegate = fuse_object
225
475
  define_fuse_methods(fuse_object)
476
+ @debug = false
477
+ self.debug=$DEBUG
226
478
  super(mountpoint,options)
227
479
  end
228
480
 
481
+ # USR1 sig handler - toggle debugging of fuse methods
482
+ # @return [void]
483
+ def sigusr1()
484
+ self.debug=!@debug
485
+ end
486
+
487
+ # RFuse Debugging status
488
+ #
489
+ # @note this is independent of the Fuse kernel module debugging enabled with the "-d" mount option
490
+ #
491
+ # @return [Boolean] whether debugging information should be printed to $stderr around each fuse method.
492
+ # Defaults to $DEBUG
493
+ # @since 1.1.0
494
+ # @see #sigusr1
495
+ def debug?
496
+ @debug
497
+ end
498
+
499
+ # Set debugging on or off
500
+ # @param [Boolean] value enable or disable debugging
501
+ # @return [Boolean] the new debug value
502
+ # @since 1.1.0
503
+ def debug=(value)
504
+ value = value ? true : false
505
+ if @debug && !value
506
+ $stderr.puts "=== #{ self }.debug=false"
507
+ elsif !@debug && value
508
+ $stderr.puts "=== #{ self }.debug=true"
509
+ end
510
+ @debug = value
511
+ end
512
+
513
+ # @private
514
+ def to_s
515
+ "#{self.class.name}::#{@fuse_delegate}"
516
+ end
229
517
  private
518
+
230
519
  def define_fuse_methods(fuse_object)
231
- #Wrap all the rfuse methods in a context block
232
520
  FUSE_METHODS.each do |method|
233
521
  if fuse_object.respond_to?(method)
234
522
  method_name = method.id2name
235
523
  instance_eval(<<-EOM, "(__FUSE_DELEGATE__)",1)
236
524
  def #{method_name} (*args,&block)
237
525
  begin
238
- $stderr.puts "==> #{ self }.#{ method_name }(\#{args.inspect })" if $DEBUG
526
+ $stderr.puts "==> \#{ self }.#{ method_name }(\#{args.inspect })" if debug?
239
527
  result = @fuse_delegate.send(:#{method_name},*args,&block)
240
- $stderr.puts "<== #{ self }.#{ method_name }()" if $DEBUG
528
+ $stderr.puts "<== \#{ self }.#{ method_name }()" if debug?
241
529
  result
242
- rescue Exception => ex
530
+ rescue => ex
243
531
  $@.delete_if{|s| /^\\(__FUSE_DELEGATE__\\):/ =~ s}
244
- $stderr.puts(ex.message) unless ex.respond_to?(:errno) || $DEBUG
532
+ $stderr.puts(ex.message) unless ex.respond_to?(:errno) || debug?
245
533
  Kernel::raise
246
534
  end
247
535
  end
@@ -250,25 +538,58 @@ module RFuse
250
538
  end
251
539
  end
252
540
 
541
+ def call_sigmethod(sigmethod)
542
+ $stderr.puts "==> #{ self }.#{ sigmethod }()" if debug?
543
+ dlg = @fuse_delegate.respond_to?(sigmethod) ? @fuse_delegate : self
544
+ dlg.send(sigmethod)
545
+ $stderr.puts "<== #{ self }.#{ sigmethod }()" if debug?
546
+ end
547
+
548
+ def respond_sigmethod?(sigmethod)
549
+ @fuse_delegate.respond_to?(sigmethod) || self.respond_to?(sigmethod)
550
+ end
551
+
552
+
253
553
  end #class FuseDelegator
254
554
 
555
+ class Context
556
+ # @private
557
+ def to_s
558
+ "Context::u#{uid},g#{gid},p#{pid}"
559
+ end
560
+ end
561
+
562
+ class Filler
563
+ # @private
564
+ def to_s
565
+ "Filler::[]"
566
+ end
567
+ end
568
+
569
+ class FileInfo
570
+ # @private
571
+ def to_s
572
+ "FileInfo::fh->#{fh}"
573
+ end
574
+ end
575
+
255
576
  # Helper class to return from :getattr method
256
577
  class Stat
257
578
  # Format mask
258
- S_IFMT = 0170000
259
- # Directory
579
+ S_IFMT = 0170000
580
+ # Directory
260
581
  S_IFDIR = 0040000
261
582
  # Character device
262
583
  S_IFCHR = 0020000
263
584
  # Block device
264
585
  S_IFBLK = 0060000
265
- # Regular file
586
+ # Regular file
266
587
  S_IFREG = 0100000
267
- # FIFO.
588
+ # FIFO.
268
589
  S_IFIFO = 0010000
269
- # Symbolic link
590
+ # Symbolic link
270
591
  S_IFLNK = 0120000
271
- # Socket
592
+ # Socket
272
593
  S_IFSOCK = 0140000
273
594
 
274
595
  # @param [Fixnum] mode file permissions
data/rfuse.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
 
24
24
  s.add_development_dependency("rake")
25
25
  s.add_development_dependency("rake-compiler")
26
- s.add_development_dependency("rspec")
26
+ s.add_development_dependency("rspec","~> 3.0.0")
27
27
  s.add_development_dependency("yard")
28
28
  s.add_development_dependency("redcarpet")
29
29
  s.add_development_dependency("ffi-xattr")
data/sample/test-ruby.rb CHANGED
@@ -111,7 +111,7 @@ class MyFile
111
111
  end
112
112
  def size
113
113
  return content.size
114
- end
114
+ end
115
115
  def isdir
116
116
  false
117
117
  end
@@ -127,7 +127,7 @@ class MyFile
127
127
  end
128
128
  end
129
129
 
130
- class MyFuse
130
+ class MyFuse
131
131
 
132
132
  def initialize(root)
133
133
  @root=root
@@ -137,7 +137,7 @@ class MyFuse
137
137
  def readdir(ctx,path,filler,offset,ffi)
138
138
  d=@root.search(path)
139
139
  if d.isdir then
140
- d.each {|name,obj|
140
+ d.each {|name,obj|
141
141
  filler.push(name,obj.stat,0)
142
142
  }
143
143
  else
@@ -211,7 +211,7 @@ class MyFuse
211
211
 
212
212
  def read(ctx,path,size,offset,fi)
213
213
  d = @root.search(path)
214
- if (d.isdir)
214
+ if (d.isdir)
215
215
  raise Errno::EISDIR.new(path)
216
216
  return nil
217
217
  else
@@ -221,7 +221,7 @@ class MyFuse
221
221
 
222
222
  def write(ctx,path,buf,offset,fi)
223
223
  d=@root.search(path)
224
- if (d.isdir)
224
+ if (d.isdir)
225
225
  raise Errno::EISDIR.new(path)
226
226
  else
227
227
  d.content[offset..offset+buf.length - 1] = buf
@@ -236,7 +236,7 @@ class MyFuse
236
236
 
237
237
  def getxattr(ctx,path,name)
238
238
  d=@root.search(path)
239
- if (d)
239
+ if (d)
240
240
  value=d.getxattr(name)
241
241
  if (!value)
242
242
  value=""
@@ -307,33 +307,4 @@ class MyFuse
307
307
 
308
308
  end #class Fuse
309
309
 
310
- if ARGV.length == 0
311
- print "\n"
312
- print "Usage: [ruby [--debug]] #{$0} mountpoint [mount_options...]\n"
313
- print "\n"
314
- print " mountpoint must be an existing directory\n"
315
- print " mount_option '-h' will list supported options\n"
316
- print "\n"
317
- print " For verbose debugging output use --debug to ruby\n"
318
- print " and '-odebug' as mount_option\n"
319
- print "\n"
320
- exit(1)
321
- end
322
-
323
- fs = MyFuse.new(MyDir.new("",0777));
324
-
325
- fo = RFuse::FuseDelegator.new(fs,*ARGV)
326
-
327
- if fo.mounted?
328
- Signal.trap("TERM") { print "Caught TERM\n" ; fo.exit }
329
- Signal.trap("INT") { print "Caught INT\n"; fo.exit }
330
-
331
- begin
332
- fo.loop
333
- rescue
334
- print "Error:" + $!
335
- ensure
336
- fo.unmount if fo.mounted?
337
- print "Unmounted #{ARGV[0]}\n"
338
- end
339
- end
310
+ RFuse.main(ARGV) { fs = MyFuse.new(MyDir.new("",0777)) }