--- ./lib/Sys/Filesystem/Freebsd.pm.orig Thu Jun 1 14:10:48 2006 +++ ./lib/Sys/Filesystem/Freebsd.pm Fri Nov 30 11:53:45 2007 @@ -26,32 +26,46 @@ use FileHandle; use Carp qw(croak); +# For access to the getfsstat system call +require 'sys/syscall.ph'; +require 'sys/mount.ph'; + use vars qw($VERSION); $VERSION = '1.05' || sprintf('%d', q$Revision: 364 $ =~ /(\d+)/g); +my $sizeof; +if ( &STATFS_VERSION == 0x20030518 ) { + $sizeof = 472; # The size in bytes of the statfs structure +} else { + croak "The statfs strucuture changed version (" . &STATFS_VERSION . ")\n"; +} +# unpack format, we want the 3rd and the last 3 fields. +my $format = 'x8L' . 'x268' . 'A' . &MFSNAMELEN . ('A' . &MNAMELEN ) x 2 ; + sub new { ref(my $class = shift) && croak 'Class name required'; my %args = @_; my $self = { }; + my (@vals, $i); $args{fstab} ||= '/etc/fstab'; - $args{mtab} ||= '/etc/mtab'; - $args{xtab} ||= '/etc/lib/nfs/xtab'; + # $args{mtab} ||= '/etc/mtab'; # Does not exist on FreeBSD + $args{xtab} ||= '/var/db/mountdtab'; my @keys = qw(fs_spec fs_file fs_vfstype fs_mntops fs_freq fs_passno); - my @special_fs = qw(swap proc devpts tmpfs); + push (@Sys::Filesystem::special_fs, qw(procfs devpts devfs)); # Read the fstab my $fstab = new FileHandle; if ($fstab->open($args{fstab})) { while (<$fstab>) { next if (/^\s*#/ || /^\s*$/); - my @vals = split(/\s+/, $_); + @vals = split(/\s+/, $_); $self->{$vals[1]}->{mount_point} = $vals[1]; $self->{$vals[1]}->{device} = $vals[0]; $self->{$vals[1]}->{unmounted} = 1; - $self->{$vals[1]}->{special} = 1 if grep(/^$vals[2]$/,@special_fs); - for (my $i = 0; $i < @keys; $i++) { + $self->{$vals[1]}->{special} = 1 if grep(/^$vals[2]$/,@Sys::Filesystem::special_fs); + for ($i = 0; $i < @keys; $i++) { $self->{$vals[1]}->{$keys[$i]} = $vals[$i]; } } @@ -60,24 +74,42 @@ croak "Unable to open fstab file ($args{fstab})\n"; } - # Read the mtab - my $mtab = new FileHandle; - if ($mtab->open($args{mtab})) { - while (<$mtab>) { - next if (/^\s*#/ || /^\s*$/); - my @vals = split(/\s+/, $_); - delete $self->{$vals[1]}->{unmounted} if exists $self->{$vals[1]}->{unmounted}; - $self->{$vals[1]}->{mounted} = 1; - $self->{$vals[1]}->{mount_point} = $vals[1]; - $self->{$vals[1]}->{device} = $vals[0]; - $self->{$vals[1]}->{special} = 1 if grep(/^$vals[2]$/,qw(swap proc devpts tmpfs)); - for (my $i = 0; $i < @keys; $i++) { - $self->{$vals[1]}->{$keys[$i]} = $vals[$i]; - } + # Get the number of mounted fileystems we have + my $buf = ''; + my $cnt = syscall(&SYS_getfsstat, $buf, length $buf, &MNT_NOWAIT); + + # Fix a bug on some 5.x systems, the previous syscall may return 0... + $cnt = 20 if ( ! $cnt ); + + # Preallocate the buffer memory per the syscall() requreiments + $buf = ' ' x ( $sizeof * $cnt ); + + if ( ($cnt=syscall(&SYS_getfsstat, $buf, length $buf, &MNT_NOWAIT)) ) { + for (($i) = 0; $i < $cnt; $i++) { + + my $offset = ($i)? 'x' . ($i * $sizeof): ''; + @vals = unpack ( $offset . $format, $buf); + + delete $self->{$vals[3]}->{unmounted} if exists $self->{$vals[3]}->{unmounted}; + $self->{$vals[3]}->{mounted} = 1; + $self->{$vals[3]}->{mount_point} = $vals[3]; + $self->{$vals[3]}->{device} = $vals[2]; + $self->{$vals[3]}->{special} = 1 if grep(/^$vals[1]$/,@Sys::Filesystem::special_fs); + + $self->{$vals[3]}->{fs_spec} = $vals[2]; + $self->{$vals[3]}->{fs_file} = $vals[3]; + $self->{$vals[3]}->{fs_vfstype} = $vals[1]; + $self->{$vals[3]}->{fs_mntops} = + ($vals[0] & &MNT_RDONLY)? 'ro': 'rw'; + $self->{$vals[3]}->{fs_mntops} .= ',noexec' + if ($vals[0] & &MNT_NOEXEC); + $self->{$vals[3]}->{fs_mntops} .= ',nosuid' + if ($vals[0] & &MNT_NOSUID); + $self->{$vals[3]}->{fs_mntops} .= ',nodev' + if ($vals[0] & &MNT_NODEV); } - $mtab->close; } else { - croak "Unable to open mtab file ($args{mtab})\n"; + croak "Unable to retrieve mounted filesystem information\n"; } # Bless and return