Various changes to tests and Makefile.
authorDerrik Pates <demon@now.ai>
Sun, 3 Jul 2011 18:07:59 +0000 (12:07 -0600)
committerDerrik Pates <demon@now.ai>
Sun, 3 Jul 2011 18:07:59 +0000 (12:07 -0600)
Merged all loopback scripts into a single variant; now threads are
enabled by passing --use-threads to loopback.pl instead of having a
separate script variant, and use of Filesys::Statvfs instead of
bogus filler statfs() data is enabled with --use-real-statfs. Also,
loopback now fork()s itself away into a daemon, rather than depending
on external infrastructure to do it; --pidfile can be passed to create
a PID file.

Altered test/helper.pm and test/s/mount.t to use new loopback.pl semantics.

Altered test/statfs.t to optionally use Filesys::Statvfs's statvfs()
instead of raw syscalls and pack masks, if the option is available
to us. If not available, it will try to use syscalls instead.

Cleanups to Makefile to put different options where they belong,
rather than e.g., abusing the 'OBJECT' list to specify libraries
and such. Works with all platforms.

Updates to README and MANIFEST.

MANIFEST
Makefile.PL
README
examples/loopback-statvfs.pl [deleted file]
examples/loopback.pl
examples/loopback_t.pl [deleted file]
test/helper.pm
test/s/mount.t
test/statfs.t

index 923ad41..2a3991f 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -33,7 +33,5 @@ test/pod.t
 examples/example.pl
 examples/example_t.pl
 examples/loopback.pl
-examples/loopback_t.pl
 examples/rmount_remote.pl
 examples/rmount.pl
-examples/loopback-statvfs.pl
index f096413..e40f912 100644 (file)
@@ -12,80 +12,76 @@ use Config;
 # actually linking the library to itself. Awesome.
 package MY;
 sub test_via_harness {
-  my($self, $perl, $tests) = @_;
-  local $_ = $self->SUPER::test_via_harness($perl, $tests);
-  s/PERL_DL_NONLAZY=1//g if $^O eq 'darwin';
-  return $_;
+    my($self, $perl, $tests) = @_;
+    local $_ = $self->SUPER::test_via_harness($perl, $tests);
+    s/PERL_DL_NONLAZY=1//g if $^O eq 'darwin';
+    return $_;
 }
 
 sub test_via_script {
-  my($self, $perl, $tests) = @_;
-  local $_ = $self->SUPER::test_via_script($perl, $tests);
-  s/PERL_DL_NONLAZY=1//g if $^O eq 'darwin';
-  return $_;
+    my($self, $perl, $tests) = @_;
+    local $_ = $self->SUPER::test_via_script($perl, $tests);
+    s/PERL_DL_NONLAZY=1//g if $^O eq 'darwin';
+    return $_;
 }
 
 package main;
 
-my $ver = `fusermount -V`;
-my $ver2 = `mount_fusefs -V`;
-chomp(my $ver3 = `mount_fusefs -V 2>&1 | head -n1`);
-$ver =~ s/^.*?version:\s+//;
-$ver2 =~ s/^.*?version:\s+//;
-$ver3 =~ s/^.*?version\s+//;
-if (! $ver && ! $ver2 && ! $ver3) {
-       # make CPANPLUS happy and don't report errors if fuse isn't installed
-       die("No support for os: $^O\n",
-               "You need to have fuse-dev (or similar) package installed and have sufficient permissions in order to install this module\n",
-               $^O eq 'darwin' ? ("One option on Mac is http://code.google.com/p/macfuse/\n") : (),
-       );
+chomp(my $fusever = `pkg-config --modversion fuse 2> /dev/null`);
+# Required for refuse on NetBSD
+unless ($fusever) {
+    chomp($fusever = `fusermount -V`);
+    $fusever =~ s/^.*?version:\s+//;
 }
-if ($ver && $ver + 0 < 2.5) {
-       die "Fuse perl bindings need Linux fuse version 2.5 or newer\n";
-} elsif ($ver2 && $ver2 + 0 < 0.3) {
-       die "Fuse perl bindings need FreeBSD fuse version 0.3 or newer\n";
-} elsif ($^O eq 'darwin' && $ver3 && !(($ver3 ge "0.1.0b006") || ($ver3 eq "0.1.0"))) {
-       # the "ge" string-compare check will match all later revs and all later
-       # betas, but not the final release of the current rev (0.1.0).
-       die "Fuse perl bindings need MacFUSE version 0.1.0b006 or newer, your version is \"$ver3\"\n";
+
+unless ($fusever) {
+    # make CPANPLUS happy and don't report errors if fuse isn't installed
+    die("No support for os: $^O\n",
+        "You need to have fuse-dev (or similar) package installed and have sufficient permissions in order to install this module\n",
+        $^O eq 'darwin' ? ("One option on Mac is http://code.google.com/p/macfuse/\n") : (),
+    );
+}
+if ($fusever && $fusever + 0 < 2.6) {
+    die "FUSE API is ", $fusever, ", must be 2.6 or later\n";
 } else {
-       warn "fuse version found: ", $ver || $ver2 || $ver3, "\n";
+    warn "fuse version found: ", $fusever, "\n";
 }
 
-my $inc = '-DFUSE_USE_VERSION=26 ' . `pkg-config --cflags fuse` || '-I ../include -D_FILE_OFFSET_BITS=64';
-my $obj = `pkg-config --libs fuse` || (($^O eq 'netbsd') ? '-lrefuse' : '-lfuse');
+chomp(my $inc = `pkg-config --cflags-only-I fuse 2> /dev/null` || '-I ../include');
+chomp(my $libs = `pkg-config --libs-only-L fuse 2> /dev/null`);
+chomp($libs .= `pkg-config --libs-only-l fuse 2> /dev/null` || (($^O eq 'netbsd') ? '-lrefuse' : '-lfuse'));
 if ($^O eq 'darwin' && (uname())[2] =~ /^10\./) {
-       $obj =~ s/-lfuse/-lfuse_ino64/;
+    $libs =~ s/-lfuse/-lfuse_ino64/;
 }
-my $def = '-Wall -g -ggdb';
-$def .= ' -D__FreeBSD__=10 -D_FILE_OFFSET_BITS=64' if $^O eq 'darwin';
+chomp(my $def = '-Wall -g -ggdb -DFUSE_USE_VERSION=26 ' . `pkg-config --cflags-only-other fuse 2> /dev/null` || '-D_FILE_OFFSET_BITS=64');
+chomp($def .= `pkg-config --libs-only-other fuse 2> /dev/null`);
 $def .= ' -DPERL_HAS_64BITINT' if $Config{'use64bitint'};
 
 WriteMakefile(
-       'NAME'                  => 'Fuse',
-       'VERSION_FROM'  => 'Fuse.pm', # finds $VERSION
-       'PREREQ_PM'             => {}, # e.g., Module::Name => 1.1
-       ($] >= 5.005 ?  ## Add these new keywords supported since 5.005
-               (ABSTRACT_FROM  => 'Fuse.pm', # retrieve abstract from module
-               AUTHOR                  => 'Mark Glines <mark@glines.org>') : ()),
-               ($ExtUtils::MakeMaker::VERSION < 6.46 ? () : (
-                       META_MERGE => {
-                               resources => {
-                               bugtracker => 'https://rt.cpan.org/Public/Dist/Display.html?Name=Fuse',
-                               repository => 'http://github.com/dpavlin/perl-fuse'
-                       }
-               })
-       ),
-       'LIBS'                  => [''], # e.g., '-lm'
-       'DEFINE'                => $def, # e.g., '-DHAVE_SOMETHING'
+    'NAME'          => 'Fuse',
+    'VERSION_FROM'  => 'Fuse.pm', # finds $VERSION
+    'PREREQ_PM'     => {}, # e.g., Module::Name => 1.1
+    ($] >= 5.005 ?  ## Add these new keywords supported since 5.005
+       (ABSTRACT_FROM   => 'Fuse.pm', # retrieve abstract from module
+        AUTHOR          => 'Mark Glines <mark@glines.org>') : ()),
+    ($ExtUtils::MakeMaker::VERSION < 6.46 ? () : (
+        META_MERGE => {
+            resources => {
+                bugtracker => 'https://rt.cpan.org/Public/Dist/Display.html?Name=Fuse',
+                repository => 'http://github.com/dpavlin/perl-fuse'
+            },
+        })
+    ),
+       'LIBS'          => '-lpthread ' . $libs, # e.g., '-lm'
+       'DEFINE'        => $def, # e.g., '-DHAVE_SOMETHING'
        # Insert -I. if you add *.h files later:
-       'INC'                   => $inc, # e.g., '-I/usr/include/other'
+       'INC'           => $inc, # e.g., '-I/usr/include/other'
        # Un-comment this if you add C files to link with later:
-       'OBJECT'                => "$obj Fuse.o -lpthread", # link all the C files too
+       'OBJECT'        => 'Fuse$(OBJ_EXT)', # link all the C files too
 );
 
 sub MY::postamble {
-       return <<'MAKE_MORE';
+    return <<'MAKE_MORE';
 
 cpan:
        make clean
@@ -104,3 +100,5 @@ sf:
 
 MAKE_MORE
 };
+
+# vim: ts=4 ai et hls
diff --git a/README b/README
index 1a66bce..4a60518 100644 (file)
--- a/README
+++ b/README
@@ -12,8 +12,6 @@ database as file system, but there will be more.
 This is a pre-production release.  It seems to work quite well.  In fact, I
 can't find any problems with it whatsoever.  If you do, I want to know.
 
-Support for FreeBSD is experimental, so expect tests to fail.
-
 INSTALLATION
 
 To install this module type the standard commands as root:
@@ -100,3 +98,6 @@ which correct the issues that cause the test failures. However, there is
 still a bug in librefuse that causes readdir() to only be called once.
 We will be addressing this with the appropriate developers in the near
 future.
+
+Also note that on NetBSD and FreeBSD, extended attributes do not work. These
+are specifics related to the FUSE implementations on those platforms.
diff --git a/examples/loopback-statvfs.pl b/examples/loopback-statvfs.pl
deleted file mode 100755 (executable)
index 66f1abf..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use blib;
-use Fuse;
-use IO::File;
-use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT);
-use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET);
-require 'syscall.ph'; # for SYS_mknod and SYS_lchown
-use Filesys::Statvfs;
-
-my $tmp_path = "/tmp/fusetest-" . $ENV{LOGNAME};
-if (! -e $tmp_path) {
-       mkdir($tmp_path) || die "can't create $tmp_path: $!";
-}
-
-sub fixup { return $tmp_path . shift }
-
-sub x_getattr {
-       my ($file) = fixup(shift);
-       my (@list) = lstat($file);
-       return -$! unless @list;
-       return @list;
-}
-
-sub x_getdir {
-       my ($dirname) = fixup(shift);
-       unless(opendir(DIRHANDLE,$dirname)) {
-               return -ENOENT();
-       }
-       my (@files) = readdir(DIRHANDLE);
-       closedir(DIRHANDLE);
-       return (@files, 0);
-}
-
-sub x_open {
-       my ($file) = fixup(shift);
-       my ($mode) = shift;
-       return -$! unless sysopen(FILE,$file,$mode);
-       close(FILE);
-       return 0;
-}
-
-sub x_read {
-       my ($file,$bufsize,$off) = @_;
-       my ($rv) = -ENOSYS();
-       my ($handle) = new IO::File;
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open($handle,$file);
-       if(seek($handle,$off,SEEK_SET)) {
-               read($handle,$rv,$bufsize);
-       }
-       return $rv;
-}
-
-sub x_write {
-       my ($file,$buf,$off) = @_;
-       my ($rv);
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open(FILE,'+<',$file);
-       if($rv = seek(FILE,$off,SEEK_SET)) {
-               $rv = print(FILE $buf);
-       }
-       $rv = -ENOSYS() unless $rv;
-       close(FILE);
-       return length($buf);
-}
-
-sub err { return (-shift || -$!) }
-
-sub x_readlink { return readlink(fixup(shift)                 ); }
-sub x_unlink { return unlink(fixup(shift)) ? 0 : -$!;          }
-sub x_rmdir { return err(rmdir(fixup(shift))               ); }
-
-sub x_symlink { print "symlink\n"; return symlink(shift,fixup(shift)) ? 0 : -$!; }
-
-sub x_rename {
-       my ($old) = fixup(shift);
-       my ($new) = fixup(shift);
-       my ($err) = rename($old,$new) ? 0 : -ENOENT();
-       return $err;
-}
-sub x_link {
-       my ($from) = shift;
-       my ($to) = shift;
-       print "link $from -> $to\n";
-       my ($err) = link(fixup($from),fixup($to)) ? 0 : -$!;
-       return $err;
-}
-sub x_chown {
-       my ($fn) = fixup(shift);
-       print "nonexistent $fn\n" unless -e $fn;
-       my ($uid,$gid) = @_;
-       # perl's chown() does not chown symlinks, it chowns the symlink's
-       # target.  it fails when the link's target doesn't exist, because
-       # the stat64() syscall fails.
-       # this causes error messages when unpacking symlinks in tarballs.
-       my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
-       return $err;
-}
-sub x_chmod {
-       my ($fn) = fixup(shift);
-       my ($mode) = shift;
-       my ($err) = chmod($mode,$fn) ? 0 : -$!;
-       return $err;
-}
-sub x_truncate { return truncate(fixup(shift),shift) ? 0 : -$! ; }
-sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; }
-
-sub x_mkdir { my ($name, $perm) = @_; return 0 if mkdir(fixup($name),$perm); return -$!; }
-sub x_rmdir { return 0 if rmdir fixup(shift); return -$!; }
-
-sub x_mknod {
-       # since this is called for ALL files, not just devices, I'll do some checks
-       # and possibly run the real mknod command.
-       my ($file, $modes, $dev) = @_;
-       $file = fixup($file);
-       $! = 0;
-       syscall(&SYS_mknod,$file,$modes,$dev);
-       return -$!;
-}
-
-# kludge
-sub x_statfs {
-       my $name = fixup(shift);
-       my($bsize, $frsize, $blocks, $bfree, $bavail,
-               $files, $ffree, $favail, $fsid, $basetype, $flag,
-               $namemax, $fstr) = statvfs("/tmp") || return -$!;
-       return ($namemax, $files, $ffree, $blocks, $bavail, $bsize);
-}
-       
-my ($mountpoint) = "";
-$mountpoint = shift(@ARGV) if @ARGV;
-Fuse::main(
-       mountpoint=>$mountpoint,
-       getattr =>"main::x_getattr",
-       readlink=>"main::x_readlink",
-       getdir  =>"main::x_getdir",
-       mknod   =>"main::x_mknod",
-       mkdir   =>"main::x_mkdir",
-       unlink  =>"main::x_unlink",
-       rmdir   =>"main::x_rmdir",
-       symlink =>"main::x_symlink",
-       rename  =>"main::x_rename",
-       link    =>"main::x_link",
-       chmod   =>"main::x_chmod",
-       chown   =>"main::x_chown",
-       truncate=>"main::x_truncate",
-       utime   =>"main::x_utime",
-       open    =>"main::x_open",
-       read    =>"main::x_read",
-       write   =>"main::x_write",
-       statfs  =>"main::x_statfs",
-       threaded=>0,
-       debug => 1,
-);
index 2dea378..1df7535 100755 (executable)
 #!/usr/bin/perl -w
 use strict;
 
+use Carp ();
+local $SIG{'__WARN__'} = \&Carp::cluck;
+
+my $has_threads = 0;
+eval {
+    require threads;
+    require threads::shared;
+    1;
+} and do {
+    $has_threads = 1;
+    threads->import();
+    threads::shared->import();
+};
+
+my $has_Filesys__Statvfs = 0;
+eval {
+    require Filesys::Statvfs;
+    1;
+} and do {
+    $has_Filesys__Statvfs = 1;
+    Filesys::Statvfs->import();
+};
+
 use blib;
 use Fuse;
 use IO::File;
 use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT);
 use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET S_ISREG S_ISFIFO S_IMODE);
+use Getopt::Long;
+
+my %extraopts = ( 'threaded' => 0, 'debug' => 0 );
+my($use_real_statfs, $pidfile);
+GetOptions(
+    'use-threads'       => sub {
+        if ($has_threads) {
+            $extraopts{'threaded'} = 1;
+        }
+    },
+    'debug'             => sub {
+        $extraopts{'debug'} = 1;
+    },
+    'use-real-statfs'   => \$use_real_statfs,
+    'pidfile=s'         => \$pidfile,
+) || die('Error parsing options');
+
 my $can_syscall = eval {
-       require 'syscall.ph'; # for SYS_mknod and SYS_lchown
+    require 'sys/syscall.ph'; # for SYS_mknod and SYS_lchown
 };
 if (!$can_syscall && open my $fh, '<', '/usr/include/sys/syscall.h') {
-       my %sys = do { local $/ = undef;
-                       <$fh> =~ m/\#define \s+ (\w+) \s+ (\d+)/gxms;
+    my %sys = do { local $/ = undef;
+            <$fh> =~ m/\#define \s+ (\w+) \s+ (\d+)/gxms;
         };
-       close $fh;
-       if ($sys{SYS_mknod} && $sys{SYS_lchown}) {
-               *SYS_mknod  = sub { $sys{SYS_mknod}  };
-               *SYS_lchown = sub { $sys{SYS_lchown} };
-               $can_syscall = 1;
-       }
+    close $fh;
+    if ($sys{SYS_mknod} && $sys{SYS_lchown}) {
+        *SYS_mknod  = sub { $sys{SYS_mknod}  };
+        *SYS_lchown = sub { $sys{SYS_lchown} };
+        $can_syscall = 1;
+    }
 }
 
 sub fixup { return "/tmp/fusetest-" . $ENV{LOGNAME} . shift }
 
 sub x_getattr {
-       my ($file) = fixup(shift);
-       my (@list) = lstat($file);
-       return -$! unless @list;
-       return @list;
+    my ($file) = fixup(shift);
+    my (@list) = lstat($file);
+    return -$! unless @list;
+    return @list;
 }
 
 sub x_getdir {
-       my ($dirname) = fixup(shift);
-       unless(opendir(DIRHANDLE,$dirname)) {
-               return -ENOENT();
-       }
-       my (@files) = readdir(DIRHANDLE);
-       closedir(DIRHANDLE);
-       return (@files, 0);
+    my ($dirname) = fixup(shift);
+    unless(opendir(DIRHANDLE,$dirname)) {
+        return -ENOENT();
+    }
+    my (@files) = readdir(DIRHANDLE);
+    closedir(DIRHANDLE);
+    return (@files, 0);
 }
 
 sub x_open {
-       my ($file) = fixup(shift);
-       my ($mode) = shift;
-       return -$! unless sysopen(FILE,$file,$mode);
-       close(FILE);
-       return 0;
+    my ($file) = fixup(shift);
+    my ($mode) = shift;
+    return -$! unless sysopen(FILE,$file,$mode);
+    close(FILE);
+    return 0;
 }
 
 sub x_read {
-       my ($file,$bufsize,$off) = @_;
-       my ($rv) = -ENOSYS();
-       my ($handle) = new IO::File;
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open($handle,$file);
-       if(seek($handle,$off,SEEK_SET)) {
-               read($handle,$rv,$bufsize);
-       }
-       return $rv;
+    my ($file,$bufsize,$off) = @_;
+    my ($rv) = -ENOSYS();
+    my ($handle) = new IO::File;
+    return -ENOENT() unless -e ($file = fixup($file));
+    my ($fsize) = -s $file;
+    return -ENOSYS() unless open($handle,$file);
+    if(seek($handle,$off,SEEK_SET)) {
+        read($handle,$rv,$bufsize);
+    }
+    return $rv;
 }
 
 sub x_write {
-       my ($file,$buf,$off) = @_;
-       my ($rv);
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open(FILE,'+<',$file);
-       if($rv = seek(FILE,$off,SEEK_SET)) {
-               $rv = print(FILE $buf);
-       }
-       $rv = -ENOSYS() unless $rv;
-       close(FILE);
-       return length($buf);
+    my ($file,$buf,$off) = @_;
+    my ($rv);
+    return -ENOENT() unless -e ($file = fixup($file));
+    my ($fsize) = -s $file;
+    return -ENOSYS() unless open(FILE,'+<',$file);
+    if($rv = seek(FILE,$off,SEEK_SET)) {
+        $rv = print(FILE $buf);
+    }
+    $rv = -ENOSYS() unless $rv;
+    close(FILE);
+    return length($buf);
 }
 
 sub err { return (-shift || -$!) }
@@ -83,29 +123,29 @@ sub x_unlink   { return unlink(fixup(shift)) ? 0 : -$!; }
 sub x_symlink { print "symlink\n"; return symlink(shift,fixup(shift)) ? 0 : -$!; }
 
 sub x_rename {
-       my ($old) = fixup(shift);
-       my ($new) = fixup(shift);
-       my ($err) = rename($old,$new) ? 0 : -ENOENT();
-       return $err;
+    my ($old) = fixup(shift);
+    my ($new) = fixup(shift);
+    my ($err) = rename($old,$new) ? 0 : -ENOENT();
+    return $err;
 }
 sub x_link { return link(fixup(shift),fixup(shift)) ? 0 : -$! }
 sub x_chown {
-       return -ENOSYS() if ! $can_syscall;
-       my ($fn) = fixup(shift);
-       print "nonexistent $fn\n" unless -e $fn;
-       my ($uid,$gid) = @_;
-       # perl's chown() does not chown symlinks, it chowns the symlink's
-       # target.  it fails when the link's target doesn't exist, because
-       # the stat64() syscall fails.
-       # this causes error messages when unpacking symlinks in tarballs.
-       my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
-       return $err;
+    return -ENOSYS() if ! $can_syscall;
+    my ($fn) = fixup(shift);
+    print "nonexistent $fn\n" unless -e $fn;
+    my ($uid,$gid) = @_;
+    # perl's chown() does not chown symlinks, it chowns the symlink's
+    # target.  it fails when the link's target doesn't exist, because
+    # the stat64() syscall fails.
+    # this causes error messages when unpacking symlinks in tarballs.
+    my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
+    return $err;
 }
 sub x_chmod {
-       my ($fn) = fixup(shift);
-       my ($mode) = shift;
-       my ($err) = chmod($mode,$fn) ? 0 : -$!;
-       return $err;
+    my ($fn) = fixup(shift);
+    my ($mode) = shift;
+    my ($err) = chmod($mode,$fn) ? 0 : -$!;
+    return $err;
 }
 sub x_truncate { return truncate(fixup(shift),shift) ? 0 : -$! ; }
 sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; }
@@ -114,51 +154,77 @@ sub x_mkdir { my ($name, $perm) = @_; return 0 if mkdir(fixup($name),$perm); ret
 sub x_rmdir { return 0 if rmdir fixup(shift); return -$!; }
 
 sub x_mknod {
-       return -ENOSYS() if ! $can_syscall;
-       # since this is called for ALL files, not just devices, I'll do some checks
-       # and possibly run the real mknod command.
-       my ($file, $modes, $dev) = @_;
-       $file = fixup($file);
-       undef $!;
-       if ($^O eq 'freebsd' || $^O eq 'darwin' || $^O eq 'netbsd') {
-               if (S_ISREG($modes)) {
-                       open(FILE, '>', $file) || return -$!;
-                       print FILE "";
-                       close(FILE);
-                       return 0;
-               } elsif (S_ISFIFO($modes)) {
-                       my ($rv) = POSIX::mkfifo($file, S_IMODE($modes));
-                       return $rv ? 0 : -POSIX::errno();
-               }
-       }
-       syscall(&SYS_mknod,$file,$modes,$dev);
-       return -$!;
+    return -ENOSYS() if ! $can_syscall;
+    # since this is called for ALL files, not just devices, I'll do some checks
+    # and possibly run the real mknod command.
+    my ($file, $modes, $dev) = @_;
+    $file = fixup($file);
+    undef $!;
+    if ($^O eq 'freebsd' || $^O eq 'darwin' || $^O eq 'netbsd') {
+        if (S_ISREG($modes)) {
+            open(FILE, '>', $file) || return -$!;
+            print FILE '';
+            close(FILE);
+            return 0;
+        } elsif (S_ISFIFO($modes)) {
+            my ($rv) = POSIX::mkfifo($file, S_IMODE($modes));
+            return $rv ? 0 : -POSIX::errno();
+        }
+    }
+    syscall(&SYS_mknod,$file,$modes,$dev);
+    return -$!;
 }
 
 # kludge
-sub x_statfs {return 255,1000000,500000,1000000,500000,4096}
-my ($mountpoint) = "";
+sub x_statfs {
+    if ($has_Filesys__Statvfs && $use_real_statfs) {
+        (my($bsize, $frsize, $blocks, $bfree, $bavail,
+            $files, $ffree, $favail, $flag,
+            $namemax) = statvfs('/tmp')) || return -$!;
+        return ($namemax, $files, $ffree, $blocks, $bavail, $bsize);
+    }
+    return 255,1000000,500000,1000000,500000,4096;
+}
+my ($mountpoint) = '';
 $mountpoint = shift(@ARGV) if @ARGV;
+
+if (! -d $mountpoint) {
+    print STDERR "ERROR: attempted to mount to non-directory\n";
+    return -&ENOTDIR
+}
+my $pid = fork();
+die("fork() failed: $!") unless defined $pid;
+
+if ($pid > 0) {
+    # parent process
+    exit(0);
+}
+if ($pidfile) {
+    open(PIDFILE, '>', $pidfile);
+    print PIDFILE $$, "\n";
+    close(PIDFILE);
+}
 Fuse::main(
-       mountpoint=>$mountpoint,
-       getattr =>"main::x_getattr",
-       readlink=>"main::x_readlink",
-       getdir  =>"main::x_getdir",
-       mknod   =>"main::x_mknod",
-       mkdir   =>"main::x_mkdir",
-       unlink  =>"main::x_unlink",
-       rmdir   =>"main::x_rmdir",
-       symlink =>"main::x_symlink",
-       rename  =>"main::x_rename",
-       link    =>"main::x_link",
-       chmod   =>"main::x_chmod",
-       chown   =>"main::x_chown",
-       truncate=>"main::x_truncate",
-       utime   =>"main::x_utime",
-       open    =>"main::x_open",
-       read    =>"main::x_read",
-       write   =>"main::x_write",
-       statfs  =>"main::x_statfs",
-       threaded=>0,
-       debug => 1,
+    'mountpoint'    => $mountpoint,
+    'getattr'       => 'main::x_getattr',
+    'readlink'      => 'main::x_readlink',
+    'getdir'        => 'main::x_getdir',
+    'mknod'         => 'main::x_mknod',
+    'mkdir'         => 'main::x_mkdir',
+    'unlink'        => 'main::x_unlink',
+    'rmdir'         => 'main::x_rmdir',
+    'symlink'       => 'main::x_symlink',
+    'rename'        => 'main::x_rename',
+    'link'          => 'main::x_link',
+    'chmod'         => 'main::x_chmod',
+    'chown'         => 'main::x_chown',
+    'truncate'      => 'main::x_truncate',
+    'utime'         => 'main::x_utime',
+    'open'          => 'main::x_open',
+    'read'          => 'main::x_read',
+    'write'         => 'main::x_write',
+    'statfs'        => 'main::x_statfs',
+    %extraopts,
 );
+
+# vim: ts=4 ai et hls
diff --git a/examples/loopback_t.pl b/examples/loopback_t.pl
deleted file mode 100755 (executable)
index 863a3f4..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/usr/bin/perl -w
-use strict;
-use threads;
-use threads::shared;
-
-use blib;
-use Fuse;
-use IO::File;
-use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT);
-use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET S_ISREG S_ISFIFO S_IMODE);
-my $can_syscall = eval {
-       require 'syscall.ph'; # for SYS_mknod and SYS_lchown
-};
-if (!$can_syscall && open my $fh, '<', '/usr/include/sys/syscall.h') {
-       my %sys = do { local $/ = undef;
-                       <$fh> =~ m/\#define \s+ (\w+) \s+ (\d+)/gxms;
-        };
-       close $fh;
-       if ($sys{SYS_mknod} && $sys{SYS_lchown}) {
-               *SYS_mknod  = sub { $sys{SYS_mknod}  };
-               *SYS_lchown = sub { $sys{SYS_lchown} };
-               $can_syscall = 1;
-       }
-}
-
-sub fixup { return "/tmp/fusetest-" . $ENV{LOGNAME} . shift }
-
-sub x_getattr {
-       my ($file) = fixup(shift);
-       my (@list) = lstat($file);
-       return -$! unless @list;
-       return @list;
-}
-
-sub x_getdir {
-       my ($dirname) = fixup(shift);
-       unless(opendir(DIRHANDLE,$dirname)) {
-               return -ENOENT();
-       }
-       my (@files) = readdir(DIRHANDLE);
-       closedir(DIRHANDLE);
-       return (@files, 0);
-}
-
-sub x_open {
-       my ($file) = fixup(shift);
-       my ($mode) = shift;
-       return -$! unless sysopen(FILE,$file,$mode);
-       close(FILE);
-       return 0;
-}
-
-sub x_read {
-       my ($file,$bufsize,$off) = @_;
-       my ($rv) = -ENOSYS();
-       my ($handle) = new IO::File;
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open($handle,$file);
-       if(seek($handle,$off,SEEK_SET)) {
-               read($handle,$rv,$bufsize);
-       }
-       return $rv;
-}
-
-sub x_write {
-       my ($file,$buf,$off) = @_;
-       my ($rv);
-       return -ENOENT() unless -e ($file = fixup($file));
-       my ($fsize) = -s $file;
-       return -ENOSYS() unless open(FILE,'+<',$file);
-       if($rv = seek(FILE,$off,SEEK_SET)) {
-               $rv = print(FILE $buf);
-       }
-       $rv = -ENOSYS() unless $rv;
-       close(FILE);
-       return length($buf);
-}
-
-sub err { return (-shift || -$!) }
-
-sub x_readlink { return readlink(fixup(shift));         }
-sub x_unlink   { return unlink(fixup(shift)) ? 0 : -$!; }
-
-sub x_symlink { print "symlink\n"; return symlink(shift,fixup(shift)) ? 0 : -$!; }
-
-sub x_rename {
-       my ($old) = fixup(shift);
-       my ($new) = fixup(shift);
-       my ($err) = rename($old,$new) ? 0 : -ENOENT();
-       return $err;
-}
-sub x_link { return link(fixup(shift),fixup(shift)) ? 0 : -$! }
-sub x_chown {
-       return -ENOSYS() if ! $can_syscall;
-       my ($fn) = fixup(shift);
-       print "nonexistent $fn\n" unless -e $fn;
-       my ($uid,$gid) = @_;
-       # perl's chown() does not chown symlinks, it chowns the symlink's
-       # target.  it fails when the link's target doesn't exist, because
-       # the stat64() syscall fails.
-       # this causes error messages when unpacking symlinks in tarballs.
-       my ($err) = syscall(&SYS_lchown,$fn,$uid,$gid,$fn) ? -$! : 0;
-       return $err;
-}
-sub x_chmod {
-       my ($fn) = fixup(shift);
-       my ($mode) = shift;
-       my ($err) = chmod($mode,$fn) ? 0 : -$!;
-       return $err;
-}
-sub x_truncate { return truncate(fixup(shift),shift) ? 0 : -$! ; }
-sub x_utime { return utime($_[1],$_[2],fixup($_[0])) ? 0:-$!; }
-
-sub x_mkdir { my ($name, $perm) = @_; return 0 if mkdir(fixup($name),$perm); return -$!; }
-sub x_rmdir { return 0 if rmdir fixup(shift); return -$!; }
-
-sub x_mknod {
-       return -ENOSYS() if ! $can_syscall;
-       # since this is called for ALL files, not just devices, I'll do some checks
-       # and possibly run the real mknod command.
-       my ($file, $modes, $dev) = @_;
-       $file = fixup($file);
-       undef $!;
-       if ($^O eq 'freebsd' || $^O eq 'darwin' || $^O eq 'netbsd') {
-               if (S_ISREG($modes)) {
-                       open(FILE, '>', $file) || return -$!;
-                       print FILE "";
-                       close(FILE);
-                       return 0;
-               } elsif (S_ISFIFO($modes)) {
-                       my ($rv) = POSIX::mkfifo($file, S_IMODE($modes));
-                       return $rv ? 0 : -POSIX::errno();
-               }
-       }
-       syscall(&SYS_mknod,$file,$modes,$dev);
-       return -$!;
-}
-
-# kludge
-sub x_statfs {return 255,1000000,500000,1000000,500000,4096}
-my ($mountpoint) = "";
-$mountpoint = shift(@ARGV) if @ARGV;
-Fuse::main(
-       mountpoint=>$mountpoint,
-       getattr =>"main::x_getattr",
-       readlink=>"main::x_readlink",
-       getdir  =>"main::x_getdir",
-       mknod   =>"main::x_mknod",
-       mkdir   =>"main::x_mkdir",
-       unlink  =>"main::x_unlink",
-       rmdir   =>"main::x_rmdir",
-       symlink =>"main::x_symlink",
-       rename  =>"main::x_rename",
-       link    =>"main::x_link",
-       chmod   =>"main::x_chmod",
-       chown   =>"main::x_chown",
-       truncate=>"main::x_truncate",
-       utime   =>"main::x_utime",
-       open    =>"main::x_open",
-       read    =>"main::x_read",
-       write   =>"main::x_write",
-       statfs  =>"main::x_statfs",
-       threaded=>1,
-);
index 2b8579f..a259448 100644 (file)
@@ -6,11 +6,11 @@ use Config;
 use POSIX qw(WEXITSTATUS);
 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
 @ISA = "Exporter";
-@EXPORT_OK = qw($_loop $_point $_pidfile $_real);
+@EXPORT_OK = qw($_loop $_opts $_point $_pidfile $_real);
 my $tmp = -d '/private' ? '/private/tmp' : '/tmp';
-our($_loop, $_point, $_pidfile, $_real) = ("","$tmp/fusemnt-".$ENV{LOGNAME},"test/s/mounted.pid","$tmp/fusetest-".$ENV{LOGNAME});
-#$_loop = $^O ne 'darwin' && $Config{useithreads} ? "examples/loopback_t.pl" : "examples/loopback.pl";
-$_loop = $Config{useithreads} ? "examples/loopback_t.pl" : "examples/loopback.pl";
+our($_loop, $_point, $_pidfile, $_real, $_opts) = ('examples/loopback.pl',"$tmp/fusemnt-".$ENV{LOGNAME},"test/s/mounted.pid","$tmp/fusetest-".$ENV{LOGNAME}, '');
+$_opts = '--pidfile ' . $_pidfile;
+$_opts .= $Config{useithreads} ? ' --use-threads' : '';
 if($0 !~ qr|s/u?mount\.t$|) {
        my ($reject) = 1;
        if(open my $fh, '<', $_pidfile) {
index 2381734..46ca258 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/bin/perl -w
-use test::helper qw($_point $_loop $_real $_pidfile);
+use test::helper qw($_point $_loop $_opts $_real $_pidfile);
 use strict;
+use Errno qw(:POSIX);
 use Test::More tests => 3;
 
 sub is_mounted {
@@ -11,19 +12,16 @@ sub is_mounted {
 ok(!is_mounted(),"already mounted");
 ok(-f $_loop,"loopback exists");
 
-if(!fork()) {
-       #close(STDIN);
-       close(STDOUT);
-       close(STDERR);
-       mkdir $_point;
-       mkdir $_real;
-       `echo $$ >test/s/mounted.pid`;
-       diag "mounting $_loop to $_point";
-       open STDOUT, '>', '/tmp/fusemnt.log';
-       open STDERR, '>&', \*STDOUT;
-       exec("perl -Iblib/lib -Iblib/arch $_loop $_point");
-       exit(1);
-}
+mkdir $_point;
+mkdir $_real;
+diag "mounting $_loop to $_point";
+open REALSTDOUT, '>&STDOUT';
+open REALSTDERR, '>&STDERR';
+open STDOUT, '>', '/tmp/fusemnt.log';
+open STDERR, '>&', \*STDOUT;
+system("perl -Iblib/lib -Iblib/arch $_loop $_opts $_point");
+open STDOUT, '>&', \*REALSTDOUT;
+open STDERR, '>&', \*REALSTDERR;
 
 my ($success, $count) = (0,0);
 while ($count++ < 50 && !$success) {
index 67c9474..1a5b973 100644 (file)
@@ -2,49 +2,73 @@
 use test::helper qw($_real $_point);
 use Test::More;
 use Config;
+
+my $has_Filesys__Statvfs = 0;
+eval {
+    require Filesys::Statvfs;
+    1;
+} and do {
+    $has_Filesys__Statvfs = 1;
+    Filesys::Statvfs->import();
+};
+
+my $has_syscall = 0;
 eval {
    require 'sys/syscall.ph'; # for SYS_statfs
-} or plan skip_all => 'No syscall.ph';
+   1;
+} and do {
+    $has_syscall = 1;
+};
+
+if (!($has_syscall || $has_Filesys__Statvfs)) {
+    plan skip_all => 'No Filesys::Statvfs and no sys/syscall.ph';
+}
 
 # Maybe not the best way to do this... but it works. Only extract the values
 # we care about, so we don't have to worry about changing field ordering
 # around and other such nastiness.
 my $packmask;
-if ($^O eq 'linux') {
-    $packmask = 'x[L!]L![6]x[L]x[L]L';
-}
-elsif ($^O eq 'freebsd') {
-    $packmask = 'x[16]Qx[8]Q[2]qQqx[112]Lx[4]';
-}
-elsif ($^O eq 'netbsd') {
-    if ($Config{'use64bitint'}) {
-        # This should work for any 64-bit NetBSD...
-        $packmask = 'x[8]Lx![q]x[16]Q[3]x[8]Q[2]x[64]L';
+# Don't even bother setting up a packmask if we have Filesys::Statvfs.
+# In that case, we can just make one call, and save ourselves a ton of
+# messing around.
+if (!$has_Filesys__Statvfs) {
+    if ($^O eq 'linux') {
+        $packmask = 'x[L!]L![6]x[L]x[L]L';
     }
-    else {
-        # NetBSD's perl on 32-bit doesn't handle quadword types, and
-        # this is my workaround. Ugly, but it does the job. And yes,
-        # won't work for big values. Good thing we're not testing
-        # with any, huh?
-        if ($Config{'byteorder'} eq '1234') { # little endian
-            $packmask = 'x[4]Lx[8]Lx[4]Lx[4]Lx[4]x[8]Lx[4]Lx[4]x[64]L';
-        }
-        elsif ($Config{'byteorder'} eq '4321') { # big endian
-            $packmask = 'x[4]Lx[8]x[4]Lx[4]Lx[4]Lx[8]x[4]Lx[4]Lx[64]L';
+    elsif ($^O eq 'freebsd') {
+        $packmask = 'x[16]Qx[8]Q[2]qQqx[112]Lx[4]';
+    }
+    elsif ($^O eq 'netbsd') {
+        if ($Config{'use64bitint'}) {
+            # This should work for any 64-bit NetBSD...
+            $packmask = 'x[8]Lx![q]x[16]Q[3]x[8]Q[2]x[64]L';
         }
         else {
-            plan skip_all => "Word ordering not known, don't know how to handle statvfs1()";
-            exit(1);
+            # NetBSD's perl on 32-bit doesn't handle quadword types, and
+            # this is my workaround. Ugly, but it does the job. And yes,
+            # won't work for big values. Good thing we're not testing
+            # with any, huh?
+            if ($Config{'byteorder'} eq '1234') { # little endian
+                $packmask = 'x[4]Lx[8]Lx[4]Lx[4]Lx[4]x[8]Lx[4]Lx[4]x[64]L';
+            }
+            elsif ($Config{'byteorder'} eq '4321') { # big endian
+                $packmask = 'x[4]Lx[8]x[4]Lx[4]Lx[4]Lx[8]x[4]Lx[4]Lx[64]L';
+            }
+            else {
+                plan skip_all => "Word ordering not known, don't know how to handle statvfs1()";
+                exit(1);
+            }
         }
     }
-}
-elsif ($^O eq 'darwin') {
-    # Accurate for OS X 10.6; 10.5 and earlier may not actually correspond
-    # to this, if my understanding of statfs(2) on OS X is fair.
-    $packmask = 'x[L!]L!x[L!]L![5]';
-} else {
-    plan skip_all => 'Platform not known, need to know how to statfs';
-    exit(1);
+    elsif ($^O eq 'darwin') {
+        # Accurate for OS X 10.6; 10.5 and earlier may not actually correspond
+        # to this, if my understanding of statfs(2) on OS X is fair.
+        $packmask = 'x[L!]L!x[L!]L![5]';
+    }
+    else {
+        plan skip_all => 'Platform not known, need to know how to statfs';
+        exit(1);
+    }
 }
 
 if ($^O eq 'netbsd' || $^O eq 'darwin') {
@@ -56,17 +80,24 @@ if ($^O eq 'netbsd' || $^O eq 'darwin') {
 else {
     plan tests => 7;
 }
-# Just make the buffer large enough that we don't have to care...
-my ($statfs_data) = "\0" x 4096;
-my ($tmp) = $_point;
-if ($^O eq 'netbsd') {
-    # NetBSD doesn't have statfs(2); statvfs1(2) is its closest analogue.
-       ok(!syscall(&SYS_statvfs1,$tmp,$statfs_data,1),'statvfs1');
+my @list;
+if ($has_Filesys__Statvfs) {
+    # This is a neater way to do this - if it's available...
+    ok(@list = (statvfs($_point))[1,2,3,4,5,6,9]);
 }
-else {
-       ok(!syscall(&SYS_statfs,$tmp,$statfs_data),'statfs');
+elsif ($has_syscall) {
+    # Just make the buffer large enough that we don't have to care...
+    my ($statfs_data) = "\0" x 4096;
+    my ($tmp) = $_point;
+    if ($^O eq 'netbsd') {
+        # NetBSD doesn't have statfs(2); statvfs1(2) is its closest analogue.
+       ok(!syscall(&SYS_statvfs1,$tmp,$statfs_data,1),'statvfs1');
+    }
+    else {
+       ok(!syscall(&SYS_statfs,$tmp,$statfs_data),'statfs');
+    }
+    @list = unpack($packmask,$statfs_data);
 }
-my @list = unpack($packmask,$statfs_data);
 diag "statfs: ",join(', ', @list);
 is(shift(@list),4096,'block size');
 is(shift(@list),1000000,'blocks');