#!/usr/bin/perl
# (c) 1999/2000/2001,2002,2003 Mandriva, 
# Chmouel Boudjnah <chmouel@mandriva.com>, Denis HAVLIK <denis@mandriva.com>
# And others Coooker contributor.
# See http://www.gnu.org for license.
## Enable or disable supermount.
# $Id$

my $file = $ENV{FSTAB} || '/etc/fstab';
my ($ofile, $mpoint);

#"bad" or "nessesary" options for "normal" and "supermount" entry
# "bad" options can be regexp.
my @normal_bad = qw ( fs=\S+ dev=\S+ --);
my @super_bad = qw (sync user noauto);
my @normal_must = qw (user noauto nodev nosuid);
my @super_must = qw (nodev nosuid);
my $fs_ok = '(auto|vfat|iso9660)';
my $dev_ok = '(fd|floppy|zip|cdrom)\d*';
my $mnt_ok = '(floppy|zip|cdrom)\d*';
my ($enable, $disable, $infile);

while ($ARGV[0] =~ /^--/ || $ARGV[0] =~ /^-/) {
  $_ = shift;
  if (/^--file=([^ \t]+)/ || /^-f=([^ \t]+)/) {
    $file = $1;
  } elsif (/^--mountpoint=([^ \t]+)/ || /^-m=([^ \t]+)/) {
    $mpoint = $1;
  } elsif (/^--infile/ || /^-i/) {
    $infile++;
  } elsif (/^--help/ || /^-h/ || /^-\?/) {
    usage(0);
  } else {
    print STDERR "Unrecognized switch: $_\n";
    usage(1);
  }
}

if    ($ARGV[0] =~ /enable/) { $enable++; }
elsif ( $ARGV[0] =~ /disable/ ) { $disable++; }
else { usage(1); }

open FH, $file or die "Can't open $file\n";
if ($infile) {
  $ofile = `mktemp /tmp/fstab.XXXXXX` || die "Can't create temporary file\n"; chomp $ofile;
  open OU, ">$ofile" or die "Can't write to $ofile\n"; select OU;
}

while (<FH>) {
  my ($dev, $point, $fs, $opt, $d1, $d2) = split;
  my @opt = split (',', $opt);
  if ( $disable && ($fs eq "supermount") && (!defined($mpoint) || $point eq $mpoint) && $_ !~ /^#/ ) {
    my @must;
    map { m/^fs=(\S+)/ && ($fs = $1);
	  m/dev=(\S+)/ && ($dev= $1); } @opt;
    $fs = 'auto' if $fs =~ /:/;
    &clean_options(\@opt,\@normal_must,\@normal_bad);
    if ($dev =~ /^\/dev\/(fd[0-1]|floppy$)/ ) {
      @must = qw (sync);
      &clean_options(\@opt,\@must, []);
    } elsif (($dev =~ /^\/dev\/cdrom\d*$/) || ($fs eq "iso9660" )) {
      @must = qw (ro exec);
      &clean_options(\@opt,\@must, []);
    }
    $opt = join (',' , @opt); 
    print "$dev\t$point\t$fs $opt\t$d1 $d2\n";
    next;
} elsif ( $enable && (!defined($mpoint) || $point eq $mpoint) &&
            ( $fs eq "iso9660" || 
			  ( $_ !~ /^#/ && $fs =~ m/$fs_ok/ &&
			    ( $dev =~ /^\/dev\/($dev_ok)$/ || $point =~ m|^/mnt/($mnt_ok)$| )
			  )
	        ) &&
			 ($opt =~ m/(^|.*,)user.*/)
	    ) {
    if ($fs eq "auto") {
	if ($point =~ m,.*/cdrom\d*$, or $dev =~ m,.*/cdrom\d*$,) {
	    $fs = "udf:iso9660";
	} else {
	    $fs = "ext2:vfat";
	}
    }
    &clean_options(\@opt,\@super_must, \@super_bad);
    $opt = join (',' , @opt); 
    print "none\t$point\tsupermount\tfs=$fs,dev=$dev,--,$opt 0 0\n";
    next;
  }
  print;
}

close FH;

if ($infile) { close OU; 
	       system("cp -f", $file, "$file.old");
	       system("mv", $ofile, $file);chmod 0644, $file; }

sub clean_options {
  my ($ap_opt, $ap_must, $ap_bad) = @_;
  my $o; my %union; my @opt = @$ap_bad;
  foreach $o (@$ap_bad) {@$ap_opt = grep ( !/^$o$/ ,@$ap_opt);}
  foreach my $o (@$ap_opt, @$ap_must) { $union{$o}++;}
  @$ap_opt=keys %union;
}

sub usage {
  my $e = shift @_;
  $0 =~ s|.*/||;
  print {  $e ? STDERR : STDOUT } << "EOF";
Usage: $0 [OPTION]... <disable | enable>
Enable or disable supermount in fstab. 

  -m=DIR, --mountpoint=DIR: Specifiy single mount point to enable/disable.
			    (default: all)
  -f=FILE, --file=FILE:	    Specify an alternarte fstab file .
			    (default: /etc/fstab).
  -i,	      --infile:     Make modification directly in the file.

EOF
  exit($e);
}
__END__
 CHANGELOG:
Thu Feb 25 2001 Andrej Borsenkow <Andrej.Borsenkow@mow.siemens.ru>
- added ``--'' as delimiter for supermount fs options to avoid mount errors on fs-specific options
- added --mountpoint option to operate on single mount point
- changed condition to enable supermount to (($fs eq iso9660) || (($fs =~ m/$fs_ok) &&
 ($dev =~ /^\/dev\/($dev_ok)$/))) && ($opt =~ m/(^|.*,)user.*/ ) 
Before it tried to supermount Windows vfat partitions that were defined with user option.

Thu Apr 13 2000 Denis Havlik <denis@mandriva.com>
- moved definitions of "good" and "bad" fs-options, "allowed fs-s" and "good devices" to top of the script for easier maintainance.
-  added &clean_options(\@opt,\@must, \@bad) function, which parses the @opt
  array, adds the "must" options and removes the "bad" ones, and re-wrote the 
  while (<FH>) {} loop to take advantage of this functions.
- simplified the fstab parsing (split instead of regexp-s)
- changed the rules used to decide which mount points are going to be 
supermounted to: ($fs eq "iso9660") || (( $fs =~ m/$fs_ok/ ) &&
 (($dev =~ /^\/dev\/($dev_ok)$/) || ($opt =~ m/(^|.*,)user.*/ )) )
