#!/usr/bin/perl
# $Id: sm_mount.Linux 31932 2015-03-14 20:27:43Z atsybulnik $
# do mount manipulation for sm volumes only
#
# TBD: protection from multiple ID in vasm-info
#
# ex:
# sm_mount 0cc8e318-ddde-47f6-ac99-ec1cac3b9b4f 
# sm_mount 0cc8e318-ddde-47f6-ac99-ec1cac3b9b4f /dev/emcpowerb1
# sm_mount 0cc8e318-ddde-47f6-ac99-ec1cac3b9b4f /dev/emcpowerb1 '' probe
# sm_mount 0cc8e318-ddde-47f6-ac99-ec1cac3b9b4f '' '' probe
# sm_mount 0cc8e318-ddde-47f6-ac99-ec1cac3b9b4f '' -r probe 
#
# Notes: 
#   1. /dev/disk/by-uuid/uuid should present a prefered path 
#      in case of multi-path / dual-path / power-path etc
#   2. Linux only 
#   3. WO: uses "$APL/var/sm/disk-by-uuid" for device-mapper-multipath names 
#   4. check will setup 'label' if missing   
# ARGS ------------------------------------------------------------------------
use strict;
my $uuid=$ARGV[0];
my $dev =$ARGV[1];
my $opt =$ARGV[2];
my $mode=$ARGV[3];             # mode '' | probe | check

# CONS ------------------------------------------------------------------------
my $MNT='/vasm';
my $APL = $ENV{APL} || '/opt/sarch';
my $DMINFOMIN='/sbin/dmsetup info --noheadings -c -o minor';
my $MOUNT='/bin/mount';
my $UMOUNT="$APL/sm/sbin/sm_umount";
my $TUNE  ='/sbin/tune2fs';
my $XFSADM='/usr/sbin/xfs_admin';
my $BLKID ='/sbin/blkid';
my $DF='/bin/df -P';
#my $GRAPH="$APL/net/bin/conf_snmp_and_mrtg.pl >/dev/null 2>&1 &";
my $SYSBYUUID="/dev/disk/by-uuid";
my $SMBYUUID="$APL/var/sm/disk-by-uuid";

# PROC ------------------------------------------------------------------------
sub sm_alias {
 $_=shift;
 my $alias='NONE';
 if(-e $_) {         # protection
   if(m|/dev/mapper/|) { # costruct alias from dmsetup info
       my $minor=`$DMINFOMIN $_`; chomp $minor;
       $alias="dm-$minor";
   }elsif(m|/dev/cciss/(\w+)p\d+|){ # HP has /dev/cciss/c0d2p1 etc. 
       $alias="cciss/$1";           # TBD use partition number if future
   }else{
       $alias=$1 if /(\w+?)\d*$/;
   }
 }
 $alias;
}

sub unmount {
   my $mpoint=shift;
   $mpoint=~s|^$MNT/||;
   `$UMOUNT $mpoint`; 
}

# MAIN ========================================================================
 my $mnt="$MNT/$uuid";       # initial tipical place, may be changed
 print("MSG=CALL_ERROR\n"), exit 1 if $uuid eq ''; # uuid is not povided
 if(    $mode eq 'check') {  # check will mount and then unmount
   $mnt="$MNT/check/$uuid";
   mkdir("$MNT/check") if not -d "$MNT/check";
 }elsif($mode eq 'probe') {
   $mnt="$MNT/probe";
 }elsif($mode eq 'store') {
   $mnt="$MNT/store";
 } 
 mkdir($mnt,0755) if not -d $mnt;  # create mount point if not present
 #------------------------------unmount mountpoint if mounted
 `$DF $mnt | grep -q $mnt`; 
 unmount($mnt)      if !$?;   # mpoint in use. unmount
 if (-d "$MNT/$uuid") {
   if(not $mnt=~m|$MNT/$uuid|) {       
       `$DF $MNT/$uuid | grep -q $MNT/$uuid`;
        unmount("$MNT/$uuid") if !$?; # volume mounted still in uuid
   }
 }
 #------------------------------find if FSTYPE=ext4 and set an option
 my ($fstype)=`$BLKID -t UUID=$uuid`=~/TYPE="(\w+)"/i;
 my $opt_ext4='';
 my $opt_xfs='';
 if ($fstype eq 'ext4') {
   $opt_ext4=($?)?'':'-o nodelalloc'; 
 }
 if ($fstype eq 'xfs') {
   $opt_xfs='-o largeio,allocsize=4096k,nobarrier,swalloc';
 }
 $opt_ext4='';                # abandone nodelalloc
 #------------------------------find device if possible
                              # try to find device by UUID (multi-path)
 if( -e "$SMBYUUID/$uuid") {  # if SM has information about device
   $dev="$SMBYUUID/$uuid";    # used if device-mapper-multipath
 }else {                      # used if EMC powerpath: (TBD confirmation)
   $dev="$SYSBYUUID/$uuid" if !$dev && -e "$SYSBYUUID/$uuid";
 }
 $dev="-U$uuid"               if !$dev; #use uuid if device not defined
 $_=`$MOUNT $opt -o noexec,nosuid,noatime $opt_xfs $opt_ext4 $dev $mnt 2>&1`;
 if($?) {                       # mount error
    print "MSG=MOUNT_ERROR\nERR='$_'";
    exit $?;
 }
 #------------------------------get space and device information from df
 my %df=(TARGET=>$dev);                       # TBD if df fails
 open(DF, "$DF $mnt 2>/dev/null |");
 my @dftext=grep { /^\/dev\// } <DF>;
 close DF;
 %df=(%df,DEV=>$1,SIZE=>int($2/1024),USED=>int($3/1024),FREE=>int($4/1024),RATE=>$5)
                     if $dftext[0]=~/^(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d)+%/;
 $df{ALIAS}=sm_alias $df{DEV};
 #------------------------------get Label
 if ($fstype eq 'xfs') { # use xfs_admin
   if(open(XFSADM, "$XFSADM -ul $df{DEV} 2>/dev/null|")) {
      my %info=map{/^(.+?)\s*=\s*"?(\S*?)"?$/} grep {/^.+\s*=\s*.+/} <XFSADM>;
      close XFSADM; 
      my $name=$info{label};
      $df{NAME}=$name if $name;
      my $id=$info{UUID};
      if($id ne $uuid) {
        unmount($mnt);
        print "MSG=MOUNT_ERROR\nERR='UUID does not match; sm_scan is required'\n";
        exit 5;
      }
   }
 } else {
  if(open(TUNE,"$TUNE -l $df{DEV} 2>/dev/null|")) {
    my %info=map{/^(.+):\s+(\S.+)$/} grep {/^.+:.+/} <TUNE>;
    close TUNE; 
    my $name=$info{'Filesystem volume name'};
    $df{NAME}=$name if $name ne '<none>';
    my $id=$info{'Filesystem UUID'};
    if($id ne $uuid) {
      unmount($mnt);
      print "MSG=MOUNT_ERROR\nERR='UUID does not match; sm_scan is required'\n";
      exit 5;
    }
  }
 }
 #------------------------------get information from volume mark
 if ( -f "$mnt/.vasm-info" ) {
    if(open(INFO,"$mnt/.vasm-info")) {
      my %info=map{/(^\w+)=(.+)/} grep {/^\w+=.+/} <INFO>;
      close INFO;
      $df{ID}=$info{ID} if exists $info{ID};
      $df{NICK}=$info{NAME} if exists $info{NAME}; # remember name as nick since label was placed into NAME
    } 
 }
 $df{ID}='volume_unmarked' if not exists $df{ID}; 
 #------------------------------ unmount volume if only check
 if($mode eq 'check') {
    unmount($mnt);
    rmdir "$mnt";               # remove temporary mount point
    #--------------------------- correct label if missing
    if(not exists $df{NAME} or not $df{NAME}) { # label is missing
      if(exists $df{NICK} and $df{NICK}) {
        $_=$df{NICK};
        s/^vol/va-/ if /^vol\d+/;    # convert default name like vol0001 -> va-0001
        s/|&;\s//;                   # remove '&', ';', '|' if any
        `$TUNE -L $_ $df{DEV}`;      # set the label
        $df{NAME}=$_;
      }
    }
 }
 #------------------------------inform graph about mount
 #system($GRAPH)   if $mode ne 'check';
 #------------------------------publish results
 print "$_=$df{$_}\n"  foreach (keys %df);
 
 exit 0;
