#!/usr/bin/perl

# $Id$

# Update /etc/fstab for user-mountable devices

# $Log$

require 'getopts.pl';

$WHATDEV = '/usr/csl/bin/whatdev';
$progname = $0;

%options = (
	    "cdrom", "/mnt/cdrom:iso9660:user,ro,nosuid,nodev,noauto",
	    "zip",   "/mnt/zip:auto:user,nosuid,nodev,noauto",
	    "floppy", "/mnt/floppy:auto:user,nosuid,nodev,noauto:"
	   );

@comments = (
	     "# fix-fstab: The following entries are generated automatically\n",
	     "# fix-fstab: by fix-fstab\n",
	     "# fix-fstab: ---DO NOT HAND EDIT ANYTHING BELOW THIS LINE---\n"
	    ); 

# Magic stuff for cdrecord

$CDRFILE   = '/etc/cdrecord.conf';
$CDRNOFILE = '/var/adm/no-cdrecord-update';
$CDRSCAN   = '/usr/bin/cdrecord -scanbus';
$CDRMESG   = 'Removable CD-ROM';

$IDENOFILE = '/var/adm/no-ide-scsi-module';
$MODFILE   = '/etc/modules.conf';

if (!Getopts ("d:f:qrv")) {
  &usage();
  exit 1;
}

$debug=1;
if (defined $opt_d) {
  $debug = $opt_d;
} elsif (defined $opt_q) {
  $debug = 0;
} elsif (defined $opt_v) {
  $debug = 2;
}
$debug>1 && print "Debugging at level $debug.\n";

$file = '/etc/fstab';
if (defined ($opt_f)) {
  $file = $opt_f;
  if (! -r $file) {
    die "Can't read $file!\n";
  }
  $debug>1 && print "Updating $file.\n";
}

if (-e '/var/adm/dont-fix-fstab') {
  printf STDERR 'skipping $file update\n';
  exit 0;
}

$replacefile = 1;
if ($opt_r) {
  $replacefile = 0;
  $debug>1 && print "File replacement turned off.\n";
}

# Get the user-mountable devices out there
open (PIPE, "$WHATDEV|") || die "Ack!\n";
while (<PIPE>) {
  chomp;
  push @userdevs, $_;
  # ($type, $device) = split /:/, $_;
  # $userdevs{$type} = $device;
  $debug>2 && print "whatdev found $_\n";
}

# add the floppy disk - this never changes (yet)
# $userdevs{'floppy'} = '/dev/fd0';
push @userdevs, 'floppy:/dev/fd0';

# Now, read the fstab and write out the new one
$newfile = "$file.new";
$oldfile = "$file.bak";
open (FSTAB, $file) || die "Can't open $file!\n";
open (NEWTAB, ">$newfile") || die "Can't open $file.new!\n";
while (<FSTAB>) {
  # Don't dup my header messages
  if (/^\# fix-fstab:/) {
    next;
  }
  if (/^$/) {
    print NEWTAB;
    next;
  }
  if (/^\#/) {
    print NEWTAB;
    next;
  }
  if (!/^\s*\S+\s+(\S+)\s/) {
    print STDERR "Unknown line in $file:\n$_\n";
    exit 1;
  }
  $mntpt = $1;
  if (! ($mntpt =~ /^\/mnt\//)) {
    print NEWTAB;
    next;
  }
}
close FSTAB;

# Add comments
foreach $comment (@comments) {
  print NEWTAB $comment;
}

# Add user-mountable entries
foreach $line (sort @userdevs) {
  ($type, $dev) = split (/:/, $line);

  # Don't include /dev/hd* cdroms, as they are currently also created
  # as scsi cd roms vie the ide-scsi module
  next if ($type eq "cdrom" and $dev =~ m:/dev/hd:);

  @options = split (/:/, $options{$type});
  if ($#options>0) {
    $mntpt = shift @options;
    if ($count{$type}>0) {
      $mntpt .= $count{$type};
    }
    $count{$type}++;
    $fstype = shift @options;
    $mntopts = shift @options;
    # Zip drives get two mount points:
    #  One for zip100, called /mnt/zip, using primary partition 4
    #  One for zip250, /mnt/zip250, for disks without a partition table
    if ($type eq "zip") {
      printf NEWTAB "%-23.23s %-23.23s %-7.7s %s 0 0\n", 
      $dev, $mntpt . "250", $fstype, $mntopts;
      if (! -e $mntpt . "250") {
	mkdir $mntpt . "250", 0755;
      }
    }
    # Hack
    ($type eq "zip") and $dev .="4";
    printf NEWTAB "%-23.23s %-23.23s %-7.7s %s 0 0\n", 
      $dev, $mntpt, $fstype, $mntopts;
    if (! -e $mntpt) {
      mkdir $mntpt,0755;
    }
  }
}

close NEWTAB;

if ($replacefile) {
  link $file, $oldfile || die "Can't link $file to $oldfile!\n";
  rename $newfile, $file || die "Can't move $newfile to $file!\n";
}

&update_cdrecord();

&update_modules_conf();

exit 0;


###############################################################################
sub usage {
  local ($p1);

  $p1 = $progname;
  $p1 =~ s/.*\///g;

  print STDERR "$p1 [-d <n>] [-q] [-v]\n";
  print STDERR "\t-d <n> -- Debug at level <n> (default is 1)\n";
  print STDERR "\t-f <file> -- Change file <file> (default is /etc/fstab)\n";
  print STDERR "\t-r -- Don't change the file; just create file.new\n";
  print STDERR "\t-q -- Quiet (same as -d 0)\n";
  print STDERR "\t-v -- Verbose (same as -d 2)\n";
}

###############################################################################
# 
# Change the cdrecord default info file if the file has the magic
# header in it.

sub update_cdrecord()
{
  local ($scsi);

  # Find out if we have any scsi sd-roms.

  if (! open (CDRF, "$CDRSCAN|")) {
    $debug>1 && print STDERR "Can't exec cdrecord\n";
    return;
  }
  undef $scsi;
  while (<CDRF>) {
    chomp;
    if (/\s+(\d,\d,\d)\s+.*$CDRMESG/) {
      $scsi = $1;
      last;
    }
  }
  close CDRF;
  defined ($scsi) || return;

  $debug > 1 && print STDERR "Found scsi address $scsi\n";

  # If the config file is present, but _doesn't_ have the magic header,
  # don't change it.

  (-e $CDRNOFILE) && return;
  (-r $CDRFILE) || return;

  open (CDRR, "<$CDRFILE")     || die "Can't read $CDRFILE";
  open (CDRW, ">$CDRFILE.new") || die "Can't write $CDRFILE.new";
  while (<CDRR>) {
    s/(CDR_DEVICE=.*)/CDR_DEVICE=$scsi/;
    print CDRW;
  }
  close CDRR;
  close CDRW;

  if ($replacefile) {
    unlink "$CDRFILE.old";
    link $CDRFILE, "$CDRFILE.old";
    rename "$CDRFILE.new", $CDRFILE;
  }
}

###############################################################################
#
# Add a line for ide-scsi to modules.conf if there is an ide cd writer on
# the computer.  Also, remove the initrds to force them to be re-made later.

sub update_modules_conf()
{
  local ($drive, $line, $media, $haveit, $version);

  (-f $IDENOFILE) && return;

  $haveit=0;
  opendir (DIRH, '/proc/ide') || return;
  while (defined ($line=readdir(DIRH))) {
    chomp $line;
    if ($line =~ /hd./) {
      open (MEDIA, "/proc/ide/$line/media") || die "Can't read /proc/ide/$line/media";
      chomp ($media = <MEDIA>);
      close MEDIA;
      if ($media eq "cdrom") {
	$haveit++;
      }
    }
  }
  closedir DIRH;

  $haveit || return;

  # See if the ide-scsi line is already in /etc/modules.conf
  open (MODS, "<$MODFILE") || die "Can't read $MODFILE";
  while (<MODS>) {
    chomp;
    if (/alias\s+scsi_hostadapter\s+ide-scsi/) {
      close MODS;
      return;
    }
  }
  close MODS;

  if ($replacefile) {
    open (MODS, ">>$MODFILE") || die "Can't write to $MODFILE";
    print MODS "alias scsi_hostadapter ide-scsi\n";
    close MODS;
  }
  $debug>1 && print STDERR "echo alias scsi_hostadapter ide-scsi >> $MODFILE\n";

  # Remake the initrds
  opendir (DIRH, '/boot') || return;
  while(defined ($line=readdir(DIRH))) {
    chomp $line;
    if ($line =~ /initrd-(.*).img/) {
      $version = $1;
      $debug>1 && print STDERR "mkinitrd -f /boot/initrd-$version.img $version\n";
      $replacefile && system ("mkinitrd", "-f", "/boot/initrd-$version.img", $version);
    }
  }
  $debug>1 && print STDERR "/sbin/lilo\n";
  $replacefile && system ("/sbin/lilo");
}
