rfuse 1.0.5 → 1.1.0.RC0

Sign up to get free protection for your applications and to get access to all the features.
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)) }