#!/bin/bash
#
#  Copyright (C) 2002 Dell Computer Corporation <gary_lerhaupt@dell.com>
#
#    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#  Devlabel by Gary Lerhaupt <gary_lerhaupt@dell.com>

function readlink()
{
    # $1 = the symlink to read
    read_link=""
    if [ -L "$1" ]; then
	read_link="$1"
	while [ -L "$read_link" ]; do
	    read_link=`ls -l $read_link | sed 's/.*-> //'`
	done
    fi
}

function show_usage ()
{
    echo $"Usage: $0 [action] [options]" >&2
    echo $"      [action]  = { reload | status | add | remove | printid | reverseremap }" >&2
    echo $"      [options] = [-d device] [-s symlink] [-u UUID] [-v] [-q]" >&2
    echo $"                = [--automount] [--multipath] [--uid] [--gid] [--perms]" >&2
}

function parse_config_data()
{
    # This functions takes in 1 line of input from $CONFIG_FILE and parses it into the
    # proper format. It is able to tell if something is a UNIQUE_ID by the presence of a ":".
    # If the line is blank or is a comment, then $IGNORE_LINE is set.
    # $1 = 1 full line of input from the rawdevices file.
   
    SYMLINK=""
    DEVICE=""
    UNIQUE_ID=""
    IGNORE_LINE=""
    SYM_TYPE=""
    OPTIONS=""
    AUTOMOUNT=""
    MULTIPATH=""
    D_UID=""
    D_GID=""
    PERMS=""
    
    # Get rid of carriage returns, if necessary
    line_arg=`echo "$1" | tr -d '\r'`

    # Initially test if it is a comment or a blank line
    if [ -z "$line_arg" ] || [ `echo "$line_arg" | grep -c "^ *#"` -gt 0 ]; then
	IGNORE_LINE=1
    else
	set -- $line_arg
	SYMLINK="$1"
	DEVICE="$2"
	UNIQUE_ID="$3"
	OPTIONS="$4"

	# Figure out options
	if [ -n "$OPTIONS" ]; then
	    for config_option in `echo "$OPTIONS" | tr ',' '\n'`; do
		config_option_type=`echo "$config_option" | sed 's/=.*//' | tr A-Z a-z`
		config_option_value=`echo "$config_option" | sed 's/.*=//'`
		case $config_option_type in
		    automount)
			AUTOMOUNT="automount"
			;;
		    multipath)
			MULTIPATH="multipath"
			;;
		    uid)
			D_UID=$config_option_value
			;;
		    gid)
			D_GID=$config_option_value
			;;
		    perms)
			PERMS=$config_option_value
			;;		    
		esac
	    done
	fi

	# Figure out symtype
	if [ `echo "$SYMLINK" | grep -c "/dev/raw/raw"` -gt 0 ]; then
	    SYM_TYPE="rawdevice"
	elif [ -n "$MULTIPATH" ]; then
	    SYM_TYPE="multipath"
	else
	    SYM_TYPE="symlink"
	fi
	
	if [ -z "$SYMLINK" ] || [ -z "$DEVICE" ] || [ -z "$UNIQUE_ID" ]; then
	    echo $"" >&2
	    echo $"Ignoring bad entry: $1." >&2
	    echo $"Expecting entry to have at least 3 parameters: <SYMLINK> <DEVICE> <UUID>" >&2
	    IGNORE_LINE=1
	fi
    fi
}

function get_id()
{
    # This function determines the ID that is returned for the DEVICE
    # $1 = device
    # Returns $ID
    
    # Set variables
    ID=""
    model=""
    identifier_type=""
    dev_prefix=`echo "$1" | sed 's/.*\([hs]d[a-z]\+\).*/\1/'`
    dev_suffix=`echo "$1" | sed 's/.*[hs]d[a-z]\+//'`

    if [ -n "$dev_suffix" ] && ! `sfdisk -V /dev/$dev_prefix >/dev/null 2>&1`; then
	return 1
    fi

    # Set the ID
    if [ -n "$dev_suffix" ] && ID=`/usr/bin/partition_uuid $1 2>/dev/null` && [ -n "$ID" ]; then 
	identifier_type="partition"
	ID="P:$ID"
    elif scsi_unique_id=`/usr/bin/scsi_unique_id "$1" 2>/dev/null` && [ -n "$scsi_unique_id" ]; then 
	identifier_type="scsi"
        model=`echo "$scsi_unique_id" | grep "model:" | sed 's/model://' | tr -d " "`
	if ID=`echo "$scsi_unique_id" | grep "page83 type3:" | sed 's/page83 type3: //' | tr -d "\n"` && [ -n "$ID" ]; then
		ID="S83.3:$ID"
	elif ID=`echo "$scsi_unique_id" | grep "page83 type2:" | sed 's/page83 type2: //' | tr -d "\n"` && [ -n "$ID" ]; then
		ID="S83.2:$ID"
        elif ID=`echo "$scsi_unique_id" | grep "page83 type1:" | sed 's/page83 type1: //' | tr -d "\n"` && [ -n "$ID" ]; then
		ID="S83.1:$ID"
        elif ID=`echo "$scsi_unique_id" | grep "page80:" | grep -v "No page80" | sed 's/page80: //'  | tr -d "\n"` && [ -n "$ID" ]; then
		ID="S80:$ID"
        elif ID=`echo "$scsi_unique_id" | grep "page83 type0:" | sed 's/page83 type0: //' | tr -d "\n"` && [ -n "$ID" ]; then
		ID="S83.0:$ID"
	else
		ID="S:"
	fi
    elif [ -d /proc/ide/$dev_prefix ] && [ `cat /proc/partitions | awk '{print $4}' | grep -c "^$dev_prefix$dev_suffix$"` -eq 1 ]; then
	identifier_type="ide"
	model="`cat /proc/ide/$dev_prefix/model 2>/dev/null | tr -d " "`"
	ID="I:`cat /proc/ide/$dev_prefix/identify 2>/dev/null | tr "\n" " " | cut -d " " -f "11-20" | tr -d " "`"
    fi

    # Get the start sector for usage with non partition uuids
    start_sector=""
    if [ -n "$dev_suffix" ]; then
	start_sector=sector`partx /dev/$dev_prefix 2>/dev/null | grep "^# $dev_suffix:" | awk '{print $3}' | sed 's/-$//'`
    fi
  
    # If the identifier is scsi or ide, add the model to the end
    if [ "$identifier_type" == "scsi" ] || [ "$identifier_type" == "ide" ]; then
	ID="$ID$model$start_sector"
    fi	
}

function rotate_old_files()
{
    for old_file_number in 8 7 6 5 4 3 2 1 0; do
	new_file_number=$(($old_file_number + 1))
	mv -f $CONFIG_FILE.$old_file_number $CONFIG_FILE.$new_file_number 2>/dev/null
    done
    mv -f $CONFIG_FILE.old $CONFIG_FILE.0 2>/dev/null
}

function check_uniqueness()
{
    # This function checks a given device ID against the device_mappings array to determine if
    # it is a unique ID or not
    # $1 = the UUID to check against device_mappings
    # $2 = the SYM_TYPE being checked {symlink, rawdevice, multipath}

    IFS='
'

    if [ `echo "${device_mappings[*]}" |  grep -c "$1$"` -eq 0 ]; then
	# Cannot find any devices with this ID
	unset IFS
	return 1
    fi
    if [ `echo "${device_mappings[*]}" | grep -c "$1$"` -ne 1 ] && [ "$2" != "multipath" ]; then
	echo $"" >&2
	echo $"Uniqueness check failed.  The following devices have the same UUID:" >&2
	echo "${device_mappings[*]}" | grep $1 | sed 's/=.*//' >&2
	unset IFS
	return 2
    fi
    unset IFS
    return 0
}

function print_id()
{
    # Check that we have all the arguments
    if [ -z "$cli_device" ]; then
	echo $"" >&2
	echo $"Error! Invalid number of arguments passed." >&2
	echo $"Usage: printid [-d device]" >&2
	exit 1
    fi
    
    get_id $cli_device
    if [ -n "$ID" ]; then
	echo $ID
    else
	exit 1
    fi
}

function make_link()
{
    # This function does the actual linking of symlink to device
    # globals used: $SYM_TYPE, $SYMLINK, $DEVICE, $AUTOMOUNT, $D_UID, $D_GID, $PERMS, $UNIQUE_ID (multipath)

    if [ "$SYM_TYPE" == "symlink" ]; then
	echo $"SYMLINK: $SYMLINK -> $DEVICE"
	ln -fs $DEVICE $SYMLINK
	
	# Automount the device if AUTOMOUNT is set and its in /etc/fstab
	mountpoint=`grep "^$SYMLINK\b" /etc/fstab | head -1 | awk '{print $2}'`
	if [ -n "$AUTOMOUNT" ] && [ -n "$mountpoint" ] && [ `mount | grep -c "^$SYMLINK\b"` -eq 0 ]; then
	    mount $mountpoint
	fi
    elif [ "$SYM_TYPE" == "rawdevice" ]; then
	echo $"RAW: $SYMLINK -> $DEVICE"
	raw $SYMLINK $DEVICE 1>/dev/null
    elif [ "$SYM_TYPE" == "multipath" ]; then
	device_suffix=`echo $DEVICE | sed 's/.*[hs]d[a-z]\+\([0-9]*\)/\1/'`
	device_genericified=`echo $DEVICE | sed 's/\([hs]d\)[a-z]\+/\1#/'`
	echo $"MULTIPATH: ${SYMLINK}_multipath# -> $device_genericified"

	# Delete all multipath symlinks first
	for sym_to_delete in `ls ${SYMLINK}_multipath[0-9]* 2>/dev/null`; do
	    if [ -h "$sym_to_delete" ]; then
		rm -f "$sym_to_delete"
	    fi
	done

	# Create the new multipath symlinks
	IFS='
'
	count=0
	for multipath_dev in `echo "${device_mappings[*]}" | grep "[a-z]$device_suffix=$UNIQUE_ID" | sed 's/=.*//'`; do
	    multipath_symlink="${SYMLINK}_multipath$count"
	    echo $"     $multipath_symlink -> $multipath_dev"
	    ln -fs $multipath_dev $multipath_symlink

            # Set the ownership/permissions
	    if [ -n "$D_UID" ] || [ -n "$D_GID" ]; then
		chown $D_UID:$D_GID $multipath_dev
	    fi
	    
	    if [ -n "$PERMS" ]; then
		chmod $PERMS $multipath_dev
	    fi

	    # Automount the device if AUTOMOUNT is set and its in /etc/fstab
	    mountpoint=`grep "^$multipath_symlink\b" /etc/fstab | head -1 | awk '{print $2}'`
	    if [ -n "$AUTOMOUNT" ] && [ -n "$mountpoint" ] && [ `mount | grep -c "^$multipath_symlink\b"` -eq 0 ]; then
		mount $mountpoint
	    fi

	    count=$(($count + 1))
	done
	unset IFS
    fi
    
    # Set the ownership/permissions
    if [ -n "$D_UID" ] || [ -n "$D_GID" ]; then
	chown $D_UID:$D_GID $DEVICE
    fi

    if [ -n "$PERMS" ]; then
	chmod $PERMS $DEVICE
    fi		   
}

function remove_entry()
{
    # Check that we have all the arguments
    if [ -z "$cli_symlink" ]; then
	echo $"" >&2
	echo $"Error! Invalid number of arguments passed." >&2
	echo $"Usage: remove [-s symlink]" >&2
	exit 1
    fi

    cp -f $CONFIG_FILE $CONFIG_FILE.old 2>/dev/null
    cat $CONFIG_FILE.old | grep -v "^$cli_symlink\b" > $CONFIG_FILE 2>/dev/null
    rotate_old_files

    # If there is a difference, report back
    if [ `diff $CONFIG_FILE $CONFIG_FILE.0 | grep -c $` -gt 0 ]; then
	if [ `echo "$cli_symlink" | grep -c "/dev/raw/raw"` -gt 0 ]; then
	    SYM_TYPE="rawdevice"
	    raw $cli_symlink 0 0
	    echo $"Unbound rawdevice $cli_symlink"
	else
	    # Do multipath or symlink specific deletion stuff
	    if [ `diff $CONFIG_FILE $CONFIG_FILE.0 -n | awk {'print $4'} | grep -c "multipath"` -gt 0 ]; then
		SYM_TYPE="multipath"
		for sym_to_delete in `ls ${cli_symlink}_multipath[0-9]*`; do
		    if [ -h "$sym_to_delete" ]; then
			rm -f $sym_to_delete
			echo $"Deleted multipath $sym_to_delete"
		    fi
		done		
	    else
		SYM_TYPE="symlink"
		rm -f $cli_symlink
		echo $"Deleted symlink $cli_symlink"
	    fi
	fi
	echo $"Removed $SYM_TYPE $cli_symlink from $CONFIG_FILE"
    else
	echo $"" >&2
	echo $"Unable to find $SYM_TYPE $cli_symlink in $CONFIG_FILE" >&2
	echo $"No changes made." >&2
	exit 1
    fi
}

function add_entry()
{
    # Disable for s390 and s390x. Needs to done fairly different.
    if [ "`uname -m`" = "s390" -o "`uname -m`" = "s390x" ]; then
        echo $"" >&2
        echo $"Fdisk is not available for s390 or s390x." >&2
        echo $"Aborting device check." >&2
        exit 4
    fi

    # Check that the right arguments were passed
    if [ -z "$cli_symlink" ] || [ -z "$cli_device" ] && [ -z "$cli_uuid" ]; then
	echo $"" >&2
	echo $"Error! Invalid number of parameters passed." >&2
	echo $"Usage: add [-s symlink] [-d device]" >&2
	echo $"   or: add [-s rawdevice] [-d device]" >&2
	echo $"   or: add [-s symlink] [-u UUID]" >&2
	echo $"   or: add [-s rawdevice] [-u UUID]" >&2
	exit 1
    fi

    # Determine the $SYM_TYPE
    if [ `echo "$cli_symlink" | grep -c "/dev/raw/raw"` -gt 0 ]; then
	SYM_TYPE="rawdevice"
    elif [ -n "$cli_multipath" ]; then
	SYM_TYPE="multipath"
    else
	SYM_TYPE="symlink"
    fi

    # Make sure symlink begins with "/"
    if [ `echo "$cli_symlink" | grep -c "^/"` -eq 0 ]; then
	echo $"" >&2
	echo $"Error! Symlink does not begin with '/'". >&2
	echo $"Symlinks in devlabel must be absolute pathnames." >&2
	exit 11
    fi

    # Make sure symlink does not contain "_multipath"
    if [ `echo "$cli_symlink" | grep -c "_multipath"` -gt 0 ]; then
	echo $"" >&2
	echo $"Error! Symlink name contains a restricted phrase." >&2
	echo $"Symlink contains the phrase '_multipath'." >&2
	exit 14
    fi

    # Make sure they don't have a rawdevice with multipath
    if [ "$SYM_TYPE" == "rawdevice" ] && [ -n "$cli_multipath" ]; then
	echo $"" >&2
	echo $"Error! Rawdevice and multipath in same entry." >&2
	echo $"Rawdevices cannot be set to multipath in this manner." >&2
	exit 15
    fi
    
    # Check that $cli_symlink does not exist
    if [ -e "$cli_symlink" ] && [ "$SYM_TYPE" != "rawdevice" ]; then
	echo $"" >&2
	echo $"The file $cli_symlink already exists." >&2
	echo $"Failure. Could not create a $SYM_TYPE." >&2
	exit 3
    fi

    # Check that a symlink named $cli_symlink is not already in CONFIG_FILE
    if [ `grep -c "^$cli_symlink " $CONFIG_FILE` -gt 0 ]; then
	echo $"" >&2
	echo $"The $SYM_TYPE $cli_symlink is already in $CONFIG_FILE." >&2
	echo $"Failure. Could not add $SYM_TYPE." >&2
	exit 10
    fi

    # Check that -d and -u aren't simultaneously set
    if [ -n "$cli_uuid" ] && [ -n "$cli_device" ]; then
	echo $"" >&2
	echo $"You cannot add by uuid and by device during the same add action." >&2
	echo $"Failure.  Could not process add command." >&2
	exit 13
    fi

    # If $cli_uuid is set, find out what device it references
    if [ -n "$cli_uuid" ]; then
	check_uniqueness "$cli_uuid" "$SYM_TYPE"
	if [ "$?" -ne 0 ]; then
	    echo $"" >&2
	    echo $"Could not add a symlink to the device with this UUID." >&2
	    echo $"Either no device could be found or multiple devices have this ID." >&2
	    echo $"" >&2
	    echo $"If multiple devices have this ID because it is part of a multipath set," >&2
	    echo $"then you can add with the --multipath option to ensure device naming" >&2
	    echo $"consistency with multipath devices.  Don't use --multipath otherwise." >&22
	    exit 12
	fi
	IFS='
'
	cli_device=`echo "${device_mappings[*]}" | grep $cli_uuid | head -1 | sed 's/=.*//'`
	unset IFS
    fi
   
    # Check that $cli_device returns a UUID
    device_prefix=`echo $cli_device | sed 's/\(.*[hs]d[a-z]\+\)[0-9]*/\1/'`
    get_id $cli_device

    # Check that the device even exists
    if [ `fdisk -l $device_prefix 2>/dev/null | awk '{print $1}' | grep -c "^$cli_device$"` -eq 0 ] && [ `fdisk -l $device_prefix 2>/dev/null | awk '{print $2}' | grep -c "^$cli_device:$"` -eq 0 ]; then
	echo $"" >&2
	echo $"$cli_device does not exist." >&2
	echo $"Failure.  Since this device does not exist, it did not return an identifier." >&2
	exit 4
    fi

    # Check for a valid ID
    if [ -z "$ID" ]; then
	echo $"" >&2
	echo $"$cli_device did not return a UUID." >&2
	echo $"Failure.  Could not find a UUID for $cli_device." >&2
	exit 5
    else
	# Check that device gives a unique ID
	check_uniqueness "$ID" "$SYM_TYPE"
	return_code="$?"
	if [ "$return_code" -eq 1 ]; then
	    echo $"" >&2
	    echo $"Failure." >&2
	    echo $"The device you are trying to add to devlabel does not show up in" >&2
	    echo $"/proc/partitions." >&2
	    exit 9
	elif [ "$return_code" -gt 1 ]; then
	    echo $"" >&2
	    echo $"Failure." >&2
	    echo $"The device UUID for $cli_device is identical to other devices on your system." >&2
	    echo $"Because of this, you cannot use devlabel with this device." >&2
	    exit 6
	else
	    # Call make_link to do the linking
	    SYMLINK="$cli_symlink"
	    DEVICE="$cli_device"
	    D_UID="$cli_uid"
	    D_GID="$cli_gid"
	    PERMS="$cli_perms"
	    UNIQUE_ID="$ID"
	    make_link
	    
	    # Format the options, if any
	    options_to_write=""
	    if [ -n "$cli_automount" ]; then
		options_to_write="automount"
	    fi
	    if [ -n "$cli_multipath" ]; then
		options_to_write=`[ -n "$options_to_write" ] && echo "$options_to_write,"`"multipath"
	    fi
	    if [ -n "$cli_uid" ]; then
		options_to_write=`[ -n "$options_to_write" ] && echo "$options_to_write,"`uid=$cli_uid
	    fi
	    if [ -n "$cli_gid" ]; then
		options_to_write=`[ -n "$options_to_write" ] && echo "$options_to_write,"`gid=$cli_gid
	    fi
	    if [ -n "$cli_perms" ]; then
		options_to_write=`[ -n "$options_to_write" ] && echo "$options_to_write,"`perms=$cli_perms
	    fi
	    echo "$cli_symlink $cli_device $ID $options_to_write" >> $CONFIG_FILE
	    echo $"Added $cli_symlink to $CONFIG_FILE"
	fi
    fi
}

function startup()
{
    # Declare necessary variables
    declare -a newfile
    write_file=""

    # Parse up the CONFIG_FILE and do symlinkings
    while read line; do

	dont_link=""
 	parse_config_data "$line"
	device_prefix=`echo $DEVICE | sed 's/\(.*[hs]d[a-z]\+\)[0-9]*/\1/'`
	device_suffix=`echo $DEVICE | sed 's/.*[hs]d[a-z]\+\([0-9]*\)/\1/'`
	get_id $DEVICE

	# Check if its a comment or blank line
	if [ -n "$IGNORE_LINE" ]; then
	    newfile[${#newfile[*]}]=$line

	else

	    # Make sure that the UUID is unique before making the symlink
	    check_uniqueness "$UNIQUE_ID" "$SYM_TYPE"
	    return_code="$?"
	    if [ "$return_code" -eq 1 ]; then
		newfile[${#newfile[*]}]="$line"
		dont_link="TRUE"
		mountpoint=`grep "^$SYMLINK\b" /etc/fstab | head -1 | awk '{print $2}'`
		if [ -n "$mountpoint" ]; then
		    umount $mountpoint 2>/dev/null
		fi
		if [ "$SYM_TYPE" == "symlink" ]; then
		    rm -f $SYMLINK
		fi
		/usr/bin/logger -t devlabel -p syslog.warning "The $SYM_TYPE $SYMLINK -> $DEVICE is being ignored in $CONFIG_FILE because the correct device cannot be found."
		echo $""
		echo $"The device $DEVICE no longer seems to exist.  Because of this, the"
		echo $"$SYM_TYPE $SYMLINK -> $DEVICE will not be available. The reference"
		echo $"to this $SYM_TYPE in $CONFIG_FILE will be ignored."

	    elif [ "$return_code" -gt 1 ]; then
		newfile[${#newfile[*]}]=$line
		dont_link="TRUE"
		if [ "$SYM_TYPE" == "symlink" ]; then
		    rm -f $SYMLINK
		fi
		/usr/bin/logger -t devlabel -p syslog.warning "The $SYM_TYPE $SYMLINK -> $DEVICE is being ignored in $CONFIG_FILE due to uniqueness issues."
		echo $""
		echo $"The UUID associated with $SYMLINK is no longer absolutely unique."
		echo $"The $SYM_TYPE $SYMLINK -> $DEVICE will not be available."
		echo $"The reference to this $SYM_TYPE in $CONFIG_FILE will be ignored."

	    elif [ "$ID" != "$UNIQUE_ID" ]; then

		# Determine the new DEVICE name by searching for the UNIQUE_ID amongst all devices
		IFS='
'
		new_device="`echo "${device_mappings[*]}" | grep "=$UNIQUE_ID$" | head -1 | sed 's/=.*//'`"
		unset IFS

		# Determine if partition has just been deleted or if its been moved
	        if [ -z "$new_device" ]; then
		    newfile[${#newfile[*]}]="$line"
		    dont_link="TRUE"
		    mountpoint=`grep "^$SYMLINK\b" /etc/fstab | head -1 | awk '{print $2}'`
		    if [ -n "$mountpoint" ]; then
			umount $mountpoint 2>/dev/null
		    fi
		    if [ "$SYM_TYPE" == "symlink" ]; then
			rm -f $SYMLINK
		    fi
		    /usr/bin/logger -t devlabel -p syslog.warning "The $SYM_TYPE $SYMLINK -> $DEVICE is being ignored in $CONFIG_FILE because it cannot be found."
		    echo $""
		    echo $"The device $DEVICE no longer seems to exist.  Because of this, the"
		    echo $"$SYM_TYPE $SYMLINK -> $DEVICE will not be available. The reference"
		    echo $"to this $SYM_TYPE in $CONFIG_FILE will be ignored."
		else
		    write_file="TRUE"
		    /usr/bin/logger -t devlabel -p syslog.notice "The device $DEVICE is now known as $new_device. $SYMLINK now points to the new name."
		    echo $""
		    echo $"Device name inconsistency detected for $SYM_TYPE $SYMLINK!"
		    echo $"The device $DEVICE is now $new_device."
		    echo $"The $SYM_TYPE $SYMLINK will now point to the new device name."
		    DEVICE="$new_device"
		fi

	    fi
	    
	    # If dont_link has not been set, call make_link to do your symlinking/raw
	    if [ -z "$dont_link" ]; then  
		make_link

	        # Write to the newfile
		newfile[${#newfile[*]}]="$SYMLINK $DEVICE $UNIQUE_ID $OPTIONS"
	    fi
	fi
    done < $CONFIG_FILE

    # If any device names changed, rewrite the CONFIG_FILE, otherwise, don't touch
    if [ -n "$write_file" ]; then
	cp -f $CONFIG_FILE $CONFIG_FILE.old 2>/dev/null
	rotate_old_files
	IFS='
'
	# Save the changes
	echo -e "${newfile[*]}" > $CONFIG_FILE 2>/dev/null
	unset IFS
    fi
}

function do_reverseremap()
{
    if [ -z "$cli_force" ]; then
	echo $"" >&2
	echo $"Warning! Warning! Warning!" >&2
	echo $"To use the reverseremap function, you must also specify --force" >&2
	echo $"" >&2
	echo $"ReverseRemap can be a dangerous action to your devlabel configuration." >&2
	echo $"It wipes out the UUID values (column 3) from /etc/sysconfig/devlabel" >&2
	echo $"and using the last known device name (column 2), determines the UUID" >&2
	echo $"for that device and from then on devlabel will use that UUID to assure" >&2
	echo $"consistent access." >&2
	echo $"" >&2
	echo $"You should only use this action if you know what you are doing!  If a" >&2
	echo $"device renaming event has occurred on your system, using reverseremap will" >&2
	echo $"make devlabel ignore it and then think that no renaming event ever happened!" >&2
	exit 1
    fi

    # Declare necessary variables
    declare -a newfile

    # Parse up the CONFIG_FILE and do symlinkings
    while read line; do
	comment_out_line=""
 	parse_config_data "$line"
	get_id $DEVICE
	device_prefix=`echo $DEVICE | sed 's/\(.*[hs]d[a-z]\+\)[0-9]*/\1/'`
	device_suffix=`echo $DEVICE | sed 's/.*[hs]d[a-z]\+\([0-9]*\)/\1/'`

	# Check if its a comment or blank line
	if [ -n "$IGNORE_LINE" ]; then
	    newfile[${#newfile[*]}]=$line

	else
            # Check that the device even exists
	    if [ `fdisk -l $device_prefix 2>/dev/null | awk '{print $1}' | grep -c "^$DEVICE$"` -eq 0 ] && [ `fdisk -l $device_prefix 2>/dev/null | awk '{print $2}' | grep -c "^$DEVICE:$"` -eq 0 ]; then
		comment_out_line="(non-existant device)"
	    fi

	    # Make sure that the UUID is unique and exists
	    if [ -n "$ID" ]; then
		check_uniqueness "$ID" "$SYM_TYPE"
		return_code="$?"
		if [ "$return_code" -ne 0 ]; then
		    comment_out_line="(bad uuid returned)"
		fi
	    else
		comment_out_line="(no uuid returned)"
	    fi

	    if [ -z "$comment_out_line" ]; then
		newfile[${#newfile[*]}]="$SYMLINK $DEVICE $ID $OPTIONS"
	    else
		newfile[${#newfile[*]}]="##Commented out by reverseremap $comment_out_line: $SYMLINK $DEVICE $UNIQUE_ID $OPTIONS"
		/usr/bin/logger -t devlabel -p syslog.warning "devlabel reverseremap has commented out the entry for $DEVICE in $CONFIG_FILE $comment_out_line."
		echo $"Warning! Reverseremap has commented out the entry for $DEVICE $comment_out_line."
	    fi

	fi

    done < $CONFIG_FILE

    # Rotate files
    cp -f $CONFIG_FILE $CONFIG_FILE.old 2>/dev/null
    rotate_old_files
    IFS='
'
    # Save the changes
    echo -e "${newfile[*]}" > $CONFIG_FILE 2>/dev/null
    unset IFS
    
    echo $"REVERSE REMAP complete!"
    echo $"Run devlabel restart for the changes to take effect."
}

function show_status()
{
    # Set raw -qa variable
    raw_listing=`raw -qa`

    # Parse up the CONFIG_FILE
    while read line; do
 	parse_config_data "$line"
 
 	if [ -z "$IGNORE_LINE" ]; then
	    dev_prefix=`echo "$DEVICE" | sed 's/.*\([hs]d[a-z]\+\).*/\1/'`
	    dev_suffix=`echo "$DEVICE" | sed 's/.*[hs]d[a-z]\+//'`
	    check_uniqueness "$UNIQUE_ID" "$SYM_TYPE"
	    if [ "$?" -ne 0 ] ||  [ `cat /proc/partitions | awk '{print $4}' | grep -c "^$dev_prefix$dev_suffix$"` -eq 0 ]; then
		echo $"$SYMLINK->$DEVICE ignored. Cannot confirm UUID. No link will exist!" >&2
		[ "$SYM_TYPE" == "symlink" ] && rm -f $SYMLINK
	    else
		if [ "$SYM_TYPE" == "symlink" ]; then
		    readlink "$SYMLINK"
		    readlink_dev="$read_link"
		    if [ -e $SYMLINK ] && [ "$DEVICE" == "$readlink_dev" ]; then
			echo -e $"`ls -l $readlink_dev | awk '{print $1"\t"$3"\t"$4}'`\t$SYMLINK -> $readlink_dev"
		    else
			echo $"The $SYM_TYPE $SYMLINK does not exist.  Restart devlabel to create it!"
		    fi
		elif [ "$SYM_TYPE" == "rawdevice" ]; then
		    bound_to=`echo "$raw_listing" | grep "$SYMLINK:" | sed 's/.*bound to \(.*\)/\1/'`
		    dev_major="`ls -l $DEVICE | awk {'print $5'}`"
		    dev_minor="`ls -l $DEVICE | awk {'print $6'}`"
		    if [ `echo "$raw_listing" | grep -c "$SYMLINK:"` -gt 0 ] && [ "$bound_to" == "major $dev_major minor $dev_minor" ]; then
			echo -e $"`ls -l $DEVICE | awk '{print $1"\t"$3"\t"$4}'`\t$SYMLINK --[RAW]--> $DEVICE"
		    else
			echo $"The $SYM_TYPE $SYMLINK is currently unbound.  Restart devlabel to bind it!"
		    fi
		elif [ "$SYM_TYPE" == "multipath" ]; then
		    for multipath_symlink in `ls ${SYMLINK}_multipath* | grep "${SYMLINK}_multipath[0-9]\+$"`; do
			if [ -h "$multipath_symlink" ]; then
			    readlink "$multipath_symlink"
			    readlink_dev="$read_link"
			    if [ -e $multipath_symlink ]; then
				echo -e $"`ls -l $readlink_dev | awk '{print $1"\t"$3"\t"$4}'`\t$multipath_symlink --[MP]--> $readlink_dev"
			    else
				echo $"The $SYM_TYPE $multipath_symlink does not exist.  Restart devlabel to create it!"
			    fi
			fi
		    done
		fi
	    fi
	fi
	   
    done < $CONFIG_FILE
}

####
#### Program Starts Here
####

unset IFS

# Ugly hack to initiate first ping of device during a hotplug event so devlabel will see it later
if [ `cat /proc/$PPID/cmdline | grep -c ".agent"` -gt 0 ]; then
    devlabel status >/dev/null
fi

TEXTDOMAIN=initscripts
CONFIG_FILE=/etc/sysconfig/devlabel

[ -f /usr/bin/raw ] || exit 0
[ -f $CONFIG_FILE ] || exit 0

PATH=/usr/bin:/bin:/usr/sbin:/sbin

# Create an array of current device mappings
# Note that the only thing devlabel can currently handle are devices in /proc/partition of format hd[a-z]* or sd[a-z]*
declare -a device_mappings
for device_to_check  in `cat /proc/partitions | awk '{print $4}' | grep "[hs]d[a-z]"`; do
    get_id /dev/$device_to_check 
    device_mappings[${#device_mappings[*]}]="/dev/$device_to_check=$ID"
done

cli_device=""
cli_uuid=""
cli_symlink=""
cli_automount=""
cli_uid=""
cli_gid=""
cli_perms=""
cli_multipath=""
cli_force=""

# Parse command line arguments
action_flag=""
while [ $# -gt 0 ]; do
    case $1 in
	--device*|-d)
	    if echo $1 | grep '=' >/dev/null ; then
		cli_device=`echo $1 | sed 's/^.*=//'`
            else
                cli_device="$2"
                shift
            fi
            ;;
	--symlink*|-s)
	    if echo $1 | grep '=' >/dev/null ; then
		cli_symlink=`echo $1 | sed 's/^.*=//'`
            else
                cli_symlink="$2"
                shift
            fi
            ;;
	-u)
	    if echo $1 | grep '=' >/dev/null ; then
		cli_uuid=`echo $1 | sed 's/^.*=//'`
            else
                cli_uuid="$2"
                shift
            fi
            ;;
	--uid*)
	    if echo $1 | grep '=' >/dev/null ; then
		cli_uid=`echo $1 | sed 's/^.*=//'`
            else
                cli_uid="$2"
                shift
            fi
            ;;
	--gid*)
	    if echo $1 | grep '=' >/dev/null ; then
		cli_gid=`echo $1 | sed 's/^.*=//'`
            else
                cli_gid="$2"
                shift
            fi
            ;;
	--perms*)
	    if echo $1 | grep '=' >/dev/null ; then
		cli_perms=`echo $1 | sed 's/^.*=//'`
            else
                cli_perms="$2"
                shift
            fi
            ;;
	--automount)
	    cli_automount="automount"
	    ;;
	--multipath)
	    cli_multipath="multipath"
	    ;;
	--quiet|-q)
	    exec >/dev/null 2>&1
	    ;;
	--version|-v)
	    echo $"devlabel: 0.42.05"
	    exit 0
	    ;;
	--force)
	    cli_force="force"
	    ;;
	-*|--*)
	    echo $"" >&2
	    echo $"Error!  Unknown option: $1" >&2
	    show_usage
	    exit 3
	    ;;
	*)
	    if [ -n "$action_flag" ]; then
		echo $"" >&2
		echo $"Error!  Multiple actions specified: $action, $1" >&2
		show_usage 
		exit 4
	    fi
	    action_flag="set"
	    action="$1"
	    ;;
    esac
    shift
done

# Make sure they're root
if [ `id -u` -ne 0 ]; then
    echo $"You must be root to use this command." >&2
    exit 1
fi

# Run the specified action
case "$action" in
    start|restart|reload)
	/usr/bin/logger -t devlabel "devlabel service started/restarted"
        startup
	;;
    status)
	show_status
	;;
    add)
	add_entry
	;;
    remove)
	remove_entry
	;;
    printid)
	print_id
	;;
    reverseremap)
        do_reverseremap
	;;
    "")
	echo $"" >&2
	echo $"Error! No action was specified.">&2
	show_usage
	;;
    *)
	echo $"" >&2
	echo $"Error! Unknown action specified: $action" >&2
	show_usage
	;;
esac




