#!/usr/bin/perl
# (c) 1999, MandrakeSoft, Chmouel Boudjnah <chmouel@mandrakesoft.com>
# (c) 2000, MandrakeSoft, Denis HAVLIK <denis@mandrakesoft.com>
# See http://www.gnu.org for license.
## Enable or disable supermount.
# $Id: supermount,v 1.2 2001/06/05 07:54:19 ldv Exp $

my $file = '/etc/fstab';
my $ofile;
  
#"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);
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 ($enable, $disable, $infile);

while ($ARGV[0] =~ /^--/ || $ARGV[0] =~ /^-/) {
  $_ = shift;
  if (/^--file=([^ \t]+)/ || /^-f=([^ \t]+)/) {
    $file = $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") ) {
    my @must;
    map { m/^fs=(\S+)/ && ($fs = $1); 
	  m/dev=(\S+)/ && ($dev= $1); } @opt;
    &clean_options(\@opt,\@normal_must,\@normal_bad);
    if ($dev =~ /^\/dev\/(fd[0-1]|floppy$)/ ) {
      @must = qw (sync unhide);
      &clean_options(\@opt,\@must, []);
    } elsif (($device =~ /^\/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 && ( 
			$fs eq "iso9660" || 
			( ( $fs =~ m/$fs_ok/ ) &&
			 (   ($dev =~ /^\/dev\/($dev_ok)$/) 
			  || ($opt =~ m/(^|.*,)user.*/ )
			 )
			)
		       )
	    ) {
    &clean_options(\@opt,\@super_must, \@super_bad);
    $opt = join (',' , @opt); 
    print "$dev\t$point\tsupermount\tfs=$fs,dev=$dev,$opt 0 0\n";
    next;
  }
  print;
}

close FH;

if ($infile) { close OU; system("/bin/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. 

  -f=FILE, --file=FILE:	 Specify an alternarte fstab file (default: /etc/fstab).
  -i,	      --infile:  Modify directly in the file.

EOF
  exit($e);
}
__END__
 CHANGELOG:
Wed May 23 2001 Ivan Zakharyaschev <imz@latlinux.ru>
- put "$dev" in the first (device) field of a supermount entry (not a duplicate mount point path).
Thu Apr 13 2000 Denis Havlik <denis@mandrakesoft.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.*/ )) )
 TODO:  
add --mountpoint option to get targeted supermount-enabling/disabling on
 the single moint point. 
