# -*- Mode: Perl -*-
package Filesys::DiskSpace;
use strict;
use vars qw(@ISA @EXPORT $VERSION $DEBUG);
use Exporter;
use Config;
use Carp;
require 5.003;
@ISA = qw(Exporter);
@EXPORT = qw(df);
$VERSION = "0.05";
# known FS type numbers
my %fs_type = (
0 => "4.2", # 0x00000000
256 => "UFS", # 0x00000100
2560 => "ADVFS", # 0x00000A00
4989 => "EXT_SUPER_MAGIC", # 0x0000137D
4991 => "MINIX_SUPER_MAGIC", # 0x0000137F
5007 => "MINIX_SUPER_MAGIC2", # 0x0000138F
9320 => "MINIX2_SUPER_MAGIC", # 0x00002468
9336 => "MINIX2_SUPER_MAGIC2", # 0x00002478
19780 => "MSDOS_SUPER_MAGIC", # 0x00004d44
20859 => "SMB_SUPER_MAGIC", # 0x0000517B
22092 => "NCP_SUPER_MAGIC", # 0x0000564c
26985 => "NFS_SUPER_MAGIC", # 0x00006969
38496 => "ISOFS_SUPER_MAGIC", # 0x00009660
40864 => "PROC_SUPER_MAGIC", # 0x00009fa0
44543 => "AFFS_SUPER_MAGIC", # 0x0000ADFF
61265 => "EXT2_OLD_SUPER_MAGIC", # 0x0000EF51
61267 => "EXT2_SUPER_MAGIC", # 0x0000EF53
72020 => "UFS_MAGIC", # 0x00011954
19911021 => "_XIAFS_SUPER_MAGIC", # 0x012FD16D
19920820 => "XENIX_SUPER_MAGIC", # 0x012FF7B4
19920821 => "SYSV4_SUPER_MAGIC", # 0x012FF7B5
19920822 => "SYSV2_SUPER_MAGIC", # 0x012FF7B6
19920823 => "COH_SUPER_MAGIC", # 0x012FF7B7
4187351113 => "HPFS_SUPER_MAGIC", # 0xF995E849
);
sub df ($) {
my $dir = shift;
my ($fmt, $res, $type, $flags, $osvers, $w);
# struct fields for statfs or statvfs....
my ($bsize, $frsize, $blocks, $bfree, $bavail, $files, $ffree, $favail);
Carp::croak "Usage: df '\$dir'" unless $dir;
Carp::croak "Error: $dir is not a directory" unless -d $dir;
# try with statvfs..
eval { # will work for Solaris 2.*, OSF1 v3.2, OSF1 v4.0 and HP-UX 10.*.
{
package main;
require "sys/syscall.ph";
}
$fmt = "\0" x 512;
$res = syscall (&main::SYS_statvfs, $dir, $fmt) ;
($bsize, $frsize, $blocks, $bfree, $bavail, $files, $ffree, $favail) =
unpack "L8", $fmt;
# bsize: fundamental file system block size
# frsize: fragment size
# blocks: total blocks of frsize on fs
# bfree: total free blocks of frsize
# bavail: free blocks avail to non-superuser
# files: total file nodes (inodes)
# ffree: total free file nodes
# favail: free nodes avail to non-superuser
# to stay ok with statfs..
$type = 0; # should we try to read it from the structure ? it looks
# possible at least under Solaris.
$ffree = $favail;
$bsize = $frsize;
# $blocks -= $bfree - $bavail;
$res == 0 && defined $fs_type{$type};
}
# try with statfs..
|| eval { # will work for SunOS 4, Linux 2.0.* and 2.2.*
{
package main;
require "sys/syscall.ph";
}
$fmt = "\0" x 512;
$res = syscall (&main::SYS_statfs, $dir, $fmt);
# statfs...
if ($^O eq 'freebsd') {
# only tested with FreeBSD 3.0. Should also work with 4.0.
my ($f1, $f2);
($f1, $bsize, $f2, $blocks, $bfree, $bavail, $files, $ffree) =
unpack "L8", $fmt;
$type = 0; # read it from 'f_type' field ?
}
else {
($type, $bsize, $blocks, $bfree, $bavail, $files, $ffree) =
unpack "L7", $fmt;
}
# type: type of filesystem (see below)
# bsize: optimal transfer block size
# blocks: total data blocks in file system
# bfree: free blocks in fs
# bavail: free blocks avail to non-superuser
# files: total file nodes in file system
# ffree: free file nodes in fs
$res == 0 && defined $fs_type{$type};
}
|| eval {
{
package main;
require "sys/syscall.ph";
}
# The previous try gives an unknown fs type, it must be a different
# structure format..
$fmt = "\0" x 512;
# Try this : n2i7L119
$res = syscall (&main::SYS_statfs, $dir, $fmt);
($type, $flags, $bsize, $frsize, $blocks,
$bfree, $bavail, $files, $ffree) = unpack "n2i7", $fmt;
$res == 0 && defined $fs_type{$type};
}
# Neither statfs nor statvfs.. too bad.
|| eval {
$osvers = $Config{'osvers'};
$w = 0;
# These system normaly works but there was a problem...
# Trying to inform the user...
if ($^O eq 'solaris' || $^O eq 'dec_osf') {
# Tested. No problem if syscall.ph is present.
warn "An error occured. statvfs failed. Did you run h2ph?\n";
$w = 2;
}
if ($^O eq 'linux' || $^O eq 'freebsd') {
# Tested with linux 2.0.0 and 2.2.2
# No problem if syscall.ph is present.
warn "An error occured. statfs failed. Did you run h2ph?\n";
}
if ($^O eq 'hpux') {
if ($osvers == 9) {
# Tested. You have to change a line in syscall.ph.
warn "An error occured. statfs failed. Did you run h2ph?\n" .
"If you are using a hp9000s700, see the Df documentation\n";
}
elsif ($osvers == 10) {
# Tested. No problem if syscall.ph is present.
warn "An error occured. statvfs failed. Did you run h2ph?\n";
}
else {
# Untested
warn "An error occured. df failed. Please, submit a bug report.\n";
}
$w = 3;
}
$w;
}
|| Carp::croak "Cannot use df on this machine (untested or unsupported).";
exit if defined $w && $w > 0;
$blocks -= $bfree - $bavail;
if ($files == $ffree) {
$files = 1;
$ffree = 0;
}
warn "Warning : type $fs_type{$type} untested.. results may be incorrect\n"
unless $type != 2560 && defined $fs_type{$type};
if ($DEBUG) {
warn "Fs type : [$type] $fs_type{$type}\n" .
"total space : ", $blocks * $bsize / 1024, " Kb\n" .
"available space : ", $bavail * $bsize / 1024, " Kb\n\n";
if ($files == 1 && $ffree == 0) {
warn "inodes : no information available\n";
}
else {
warn "inodes : $files\nfree inodes : $ffree\n" .
"used inodes : ", $files - $ffree, "\n";
}
}
($type, $fs_type{$type}, ($blocks - $bavail) * $bsize / 1024,
$bavail * $bsize / 1024, $files - $ffree, $ffree);
}
1;
=head1 NAME
Filesys::DiskSpace - Perl df
=head1 SYNOPSIS
use Filesys::DiskSpace;
($fs_type, $fs_desc, $used, $avail, $fused, $favail) = df $dir;
=head1 DESCRIPTION
This routine displays information on a file system such as its type, the
amount of disk space occupied, the total disk space and the number of inodes.
It tries C<syscall(SYS_statfs)> and C<syscall(SYS_statvfs)> in several ways.
If all fails, it C<croak>s.
=head1 OPTIONS
=over 4
=item $fs_type
[number] type of the filesystem.
=item $fs_desc
[string] description of this fs.
=item $used
[number] size used (in Kb).
=item $avail
[number] size available (in Kb).
=item $ffree
[number] free inodes.
=item $fused
[number] inodes used.
=back
=head1 Installation
See the INSTALL file.
=head1 COPYRIGHT
Copyright (c) 1996-1999 Fabien Tassin. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 AUTHOR
Fabien Tassin E<lt>fta@oleane.netE<gt>
=head1 NOTES
This module was formerly called File::Df. It has been renamed into
Filesys::DiskSpace. It could have be Filesys::Df but unfortunatly
another module created in the meantime uses this name.
Tested with Perl 5.003 under these systems :
- Solaris 2.[4/5]
- SunOS 4.1.[2/3/4]
- HP-UX 9.05, 10.[1/20] (see below)
- OSF1 3.2, 4.0
- Linux 2.0.*, 2.2.*
Note for HP-UX users :
if you obtain this message :
"Undefined subroutine &main::SYS_statfs called at Filesys/DiskSpace.pm
line XXX" and if you are using a hp9000s700, then edit the syscall.ph file
(in the Perl lib tree) and copy the line containing "SYS_statfs {196;}"
outside the "if (defined &__hp9000s800)" block (around line 356).
=cut