Add support for non-privileged users and device refresh
authorBryn M. Reeves <bmr@redhat.com>
Mon, 21 Jan 2013 11:54:57 +0000 (11:54 +0000)
committerBryn M. Reeves <bmr@redhat.com>
Mon, 21 Jan 2013 11:54:57 +0000 (11:54 +0000)
Add two related features: the ability for the system administrator
(root) to define a non-root account that has permission to update
the device map and the ability for the script to automatically
request change events on modified devices.

This currently requires the nominated user to have sudo privileges
on the host. This can be removed in future versions by providing
a polkit integrated command to issue these events. This would also
simplify parsing and device verification in the script by moving
these to an external command.

blkdevalias

index d332fb5..55c4b61 100755 (executable)
@@ -39,20 +39,30 @@ BA_GROUP="$BA_DEFAULT_GROUP"
 BA_LOCK="/var/lock/blkdevalias"
 BA_SCSI_ID="/sbin/scsi_id"
 BA_SCSI_ID_FLAGS="-g -u"
+BA_READLINK="/usr/bin/readlink"
+BA_BASENAME="/bin/basename"
+BA_GETENT="/usr/bin/getent"
+BA_CHOWN="/bin/chown"
+BA_SUDO="/usr/bin/sudo"
+BA_SED="/bin/sed"
+BA_ID="/usr/bin/id"
+BA_SH="/bin/bash"
+BA_REAL_UID="$($BA_ID -u)"
+BA_REAL_GID="$($BA_ID -g)"
 
 # load config
 . $BA_CONF
 
 _error () {
-    echo "ERROR: $@" 1>&2
+    echo -e "ERROR: $@" 1>&2
 }
 
 _warn () {
-    echo "WARNING: $@" 1>&2
+    echo -e "WARNING: $@" 1>&2
 }
 
 _debug () {
-    [ "$BA_DEBUG" == "yes" ] && echo "$@" 1>&2
+    [ "$BA_DEBUG" == "yes" ] && echo -e "$@" 1>&2
 }
 
 # store the WWID map to disk
@@ -66,6 +76,10 @@ ba_store_wwid_map() {
         echo "$WWID ${WWIDMAP[$WWID]} ${TYPEMAP[$WWID]} ${PARTMAP[$WWID]}"
     done  >> $TMP_MAP
     mv $TMP_MAP $BA_MAP_PATH
+    # we may be running as root - if so re-chown the configs
+    if [ "$BA_REAL_UID" == "0" ] || [ "$BA_REAL_GID" == "0" ]; then
+        ba_chown_configs $BA_USER $BA_GROUP
+    fi
 }
 
 # read the WWID map from disk
@@ -133,7 +147,7 @@ ba_del_wwid_mapping() {
         _warn "WARNING: $WWID does not exist; doing nothing."
         return 1
     fi
-    _debug "ba_del_wwid_mapping: unsetting WWIDMAP[$WWID]"
+    _debug "\nba_del_wwid_mapping: unsetting WWIDMAP[$WWID]"
     ALIAS=${WWIDMAP[$WWID]}
     unset WWIDMAP[$WWID]
     unset NAMEMAP[$ALIAS]
@@ -168,8 +182,37 @@ ba_scsi_id () {
     else
         DEV=$(echo $DEV | sed 's/[0-9].*//')
     fi
-    _debug "ba_scsi_id: calling \"$BA_SCSI_ID $BA_SCSI_ID_FLAGS $DEV\""
-    $BA_SCSI_ID $BA_SCSI_ID_FLAGS $DEV
+     _debug "ba_scsi_id: calling \"$BA_SCSI_ID $BA_SCSI_ID_FLAGS $DEV\""
+    $BA_SUDO $BA_SCSI_ID $BA_SCSI_ID_FLAGS $DEV
+}
+
+# ba_chown_configs <user> <group>
+ba_chown_configs () {
+    local _USER _GROUP _OUT
+    _USER="$1"
+    _GROUP="$2"
+    $BA_CHOWN -R "$_USER:$_GROUP" "$BA_CONF_PATH"
+    ls -l "$BA_CONF_PATH" | while read _OUT; do
+        _debug $_OUT
+    done
+    return 0
+}
+
+# ba_refresh_device <dev path>
+ba_refresh_device () {
+    local _DEVPATH _DEVNAME _LINKDEST
+    _DEVPATH="$1"
+    _debug "refreshing device at path $_DEVPATH"
+    _LINKDEST=$($BA_READLINK $_DEVPATH)
+    if [ "$?" != 0 ]; then
+        _DEVNAME=$($BA_BASENAME $_DEVPATH | $BA_SED 's/p\+[1-9]*$//')
+        _debug "non-symlinked dev at $_DEVPATH has name $_DEVNAME"
+    else
+        _DEVNAME=$($BA_BASENAME $_LINKDEST)
+        _debug "symlinked dev at $_DEVPATH has name $_DEVNAME"
+    fi
+    _debug "requesting change uevent at sysfs path /sys/block/$_DEVNAME"
+    $BA_SUDO $BA_SH -c "echo change > /sys/block/$_DEVNAME/uevent"
 }
 
 ba_configure () {
@@ -189,16 +232,28 @@ EOF
     if [ "$_BA_USER" != "" ]; then
         BA_USER=$_BA_USER;
     fi
+    $BA_GETENT passwd "$BA_USER" &>/dev/null
+    if [ "$?" != 0 ]; then
+        _error "user (\"$BA_USER\") must be a valid user account"
+        exit 1
+    fi
+
     echo -n "Default group to own device nodes [$BA_GROUP]: "
     read _BA_GROUP
     if [ "$_BA_GROUP" != "" ]; then
         BA_GROUP=$_BA_GROUP;
     fi
+    $BA_GETENT group "$BA_GROUP" &>/dev/null
+    if [ "$?" != 0 ]; then
+        _error "user (\"$BA_GROUP\") must be a valid group account"
+        exit 1
+    fi
     echo -n "Default device directory [$BA_DEV_PATH]: "
     read _BA_DEV_PATH
     if [ "$_BA_DEV_PATH" != "" ]; then
         BA_DEV_PATH=$_BA_DEV_PATH;
     fi
+
     _debug "BA_DEV_PATH=\"$BA_DEV_PATH\""
     _debug "BA_USER=\"$BA_USER\""
     _debug "BA_GROUP=\"$BA_GROUP\""
@@ -217,6 +272,8 @@ EOF
         _error "could not create configuration file $BA_CONF"
         exit
     fi
+    # set configration ownership to reflect admin users
+    ba_chown_configs "$BA_USER" "$BA_GROUP"
     echo -e "done\n"
 }
 
@@ -249,10 +306,11 @@ ba_createdisk () {
 
     ba_add_wwid_mapping $WWID $ALIAS $TYPE $PART $DEV
     ba_store_wwid_map
+    ba_refresh_device $DEV
 }
 
 ba_deletedisk () {
-    local WWID ALIAS
+    local WWID ALIAS DEVPATH
     ALIAS=$1
     if [ "$ALIAS" == "" ]; then
         echo "Usage: $0 deletedisk <alias>"
@@ -265,9 +323,14 @@ ba_deletedisk () {
         exit 2
     fi
     echo -n "Removing wwid map disk \"$ALIAS\":"
+    # generate device path for refresh call
+    DEVPATH="/dev/$BA_DEV_PATH/${WWIDMAP[$WWID]}"
     ba_del_wwid_mapping $WWID \
-    && echo "                                  [  OK  ]"
+    && if [ "$BA_DEBUG" != "yes" ]; then
+        echo "                                  [  OK  ]"
+    fi
     ba_store_wwid_map
+    ba_refresh_device $DEVPATH
 }
 
 ba_list_disks () {