#!/usr/bin/perl -w

#
# snfsfpsrv 0.0
#
# Copyright (C)  2002 Patrice Dumas <dumas@centre-cired.fr>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#


require 5;

use strict;
use FileHandle;
use SNFS;

my $clean = 0;
my $debug = 0;
sub unlink_conf ($;$);

unless ($#ARGV < 2)
{
	print STDERR "Usage: $0 [-d] | --clean\n";
	exit 1;
}

while (@ARGV)
{
	my $arg = shift;
	if ($arg eq "-d")
	{
		$debug = 1;
	}
	elsif ($arg eq "--clean")
	{
		$clean = 1;
	}
}

my ($hostname, $conf_dir, $pid_dir, $var, $name, $user_dir);
my @conf_infos;
if (!defined(SNFS::get_conf(\@conf_infos, undef, $debug)))
{
	die "Cannot determine configuration info";
}

($hostname, $conf_dir, $pid_dir, $var, $name, $var, $var, $user_dir) 
	= @conf_infos;

# try to umount everything, unlink all config files and exit
if ($clean)
{
	my @snfsumount_command = (SNFS::SNFSUMOUNT, "-a");
	if ($debug)
	{
		push @snfsumount_command, "-d";
	}
	if (system (@snfsumount_command) != 0)
	{
		die "@snfsumount_command: error, exiting\n";
	}
	if ($< != 0)
	{
		if (unlink_conf($conf_dir, $debug))
		{
			exit 0;
		}
		exit 1;
	}
	
	my $exit_code = 0;
	my %conf_pid = ();
	SNFS::get_conf_pid (\%conf_pid);
	my @conf_dirs = keys(%conf_pid);
	unshift @conf_dirs, SNFS::ETC_PATH;
	if ($debug)
	{
		print STDERR "directories with files to unlink: @conf_dirs\n";
	}
	foreach my $conf_dir (@conf_dirs)
	{
		unless (unlink_conf($conf_dir, $debug))
		{
			$exit_code = 1;
		}
	}
	exit $exit_code;
}

# if no --clean, report status in a nice way
my %host_pid_mountprog = ();
my $ref_hosts_mountprogs;

if ($< == 0)
{
	$ref_hosts_mountprogs = &SNFS::get_hosts_mountprogs;
	if ($debug)
	{
		&SNFS::debug_hosts_mountprogs($ref_hosts_mountprogs);
	}
}

foreach my $mtab_path (SNFS::get_ftab_paths (SNFS::MTAB_PATH,0))
{
	my ($user, $mountprog);
	($user, $mountprog) = SNFS::get_mountprog($mtab_path, SNFS::MTAB_PATH);
	my %conf_pid = ();

	if ($debug)
	{
		print STDERR "Searching for $mtab_path, $mountprog\n";
	}
	
	if ($< != 0)
	{
		next if (!defined($user) or (defined($user) and $user ne $name));
		print "$mtab_path mounted with $mountprog\n";
		unless (defined($host_pid_mountprog{$mountprog}))
		{
			my ($file, $host);
			($file,$host) = SNFS::get_host ($mountprog, $conf_dir, $debug);
			my $pid = SNFS::check_rpc_psrv ($mountprog, $debug, $conf_dir, $pid_dir);
			my @host_pid = ($host, $conf_dir . '/' . $file, $pid);
			$host_pid_mountprog{$mountprog} = \@host_pid;
		}
		next;
	}
	
	if (defined($user))
	{
		print "$mtab_path mounted by $user with $mountprog\n";
	}
	else
	{
		print "$mtab_path mounted with $mountprog\n";
	}

	unless (defined($host_pid_mountprog{$mountprog}))
	{
		if (SNFS::get_conf_pid(\%conf_pid, $user))
		{
			foreach my $conf_dir (keys(%conf_pid))
			{
				my ($host, $file);
				($file, $host) = SNFS::get_host ($mountprog, $conf_dir, $debug);
				next if (!defined ($host));
				my $pid = SNFS::check_rpc_psrv ($mountprog, $debug, $conf_dir, 
					$conf_pid{$conf_dir});
				next if (!defined ($pid));
				my @host_pid = ($host, $conf_dir . '/' . $file, $pid);
				$host_pid_mountprog{$mountprog} = \@host_pid;
			}
		}
	}
}

foreach my $mountprog(values(%{$ref_hosts_mountprogs}))
{
	next if (grep { $_ == $mountprog } keys(%host_pid_mountprog));
	my ($file, $host);
	($file, $host) = SNFS::get_host ($mountprog, undef, $debug);
	my $pid = SNFS::check_rpc_psrv $mountprog;
	my @host_pid = ($host, SNFS::ETC_PATH . '/' . $file, $pid);
	$host_pid_mountprog{$mountprog} = \@host_pid;
}

foreach my $mountprog(keys(%host_pid_mountprog))
{
	my @host_pid = @{$host_pid_mountprog{$mountprog}};
	my ($host, $file, $pid);
	($host, $file, $pid) = @host_pid;
	if (!defined($host))
	{
		print "No host for $mountprog\n";
		next;
	}
	if (!defined($file))
	{
		print STDERR "$0: bug: file undef for $host\n";
		$file = "";
	}
	if ($pid)
	{
		print "rpc_psvr forwarding $mountprog to $host ($file) running: $pid\n"
	}
	else
	{
		print "rpc_psvr forwarding $mountprog to $host ($file) not running\n";
	}
}

sub unlink_conf ($;$)
{
	my $dir = shift;
	if (!defined($dir))
	{
		print STDERR "bug (unlink_conf) dir undef\n";
		return undef;
	}
	my $debug = shift;
	if (!defined($debug))
	{
		$debug = 0;
	}
	
	unless (opendir DIR, $dir)
	{
		if ($debug)
		{
			print STDERR "$0: $dir: $!\n";
		}
		return undef;
	}
	my @files;
	@files = grep
		{
			! m/^\./ &&
			! m/\.(bak|orig|old|dpkg-old|rpmnew|rpmsave|pid)$/ &&
			! m/^TEMPLATE$/ &&
			! m/~$/ &&
			! m/^#.*#$/ &&
			-f $dir . '/' . $_
		}
		readdir DIR;
	closedir DIR;
	if (! @files)
	{
		return 0;
	}
	my @unlinked_files = ();
	foreach my $file (@files)
	{
		push @unlinked_files, "$dir/$file";
	} 
	if ($debug)
	{
		print STDERR "unlinked files @unlinked_files\n";
	}
	my $remaining_files = $#unlinked_files + 1 - unlink (@unlinked_files);
	if ($remaining_files)
	{
		if ($debug)
		{
			print STDERR "$remaining_files files in $dir couldn't be removed\n";
		}
		return 0;
	}
	return 1;
}	
