#!/bin/sh -e

##########################################################################
#   Script description:
#       Change the UID for a given user
#       
#   History:
#   Date        Name        Modification
#   2015?       Jason Bacon Begin
##########################################################################

usage()
{
    cat << EOM

Usage: $0 username new-uid [directory ...]

[directory ...] is a list of directories where files owned by the old UID
will be chowned to the new.  It is highly advisable that this be "/" to
ensure that all files on the system are accessible to the user after the
UID change.  In some cases, however, this may involved searching many
directories where the user does not have files.  Use this option to save
time and resources,  but only if you know what you're doing.  Searching "/"
is the default.

EOM
    exit 1
}


##########################################################################
#   Main
##########################################################################

auto-root-check $0

if [ $# -lt 2 ]; then
    usage
fi

if [ $1 = --silent ]; then
    silent=1
    shift
    verbose=""
else
    verbose=-v
fi

user_name=$1
new_uid=$2
shift
shift

if [ $# = 0 ]; then
    dirs='/'
else
    dirs="$@"
fi
# Verify that all dirs exits before changing anything!
for dir in $dirs; do
    if [ ! -e $dir ]; then
	printf "$0: ${dir}: No such file or directory.\n"
	exit 1
    fi
done

if [ $(auto-ostype) = Darwin ]; then
    old_uid=`dscl . -read /Users/$user_name UniqueID | cut -d ' ' -f 2`
else
    old_uid=`awk -F : -v user_name=$user_name '$1 == user_name { print $3 }' /etc/passwd`
fi

# Verify that user exists
if [ 0$old_uid = 0 ]; then
    printf "$0: ${user_name}: No such user.\n"
    exit 1
fi

# Verify that new uid is not taken
old_user_name=`awk -F : -v uid=$new_uid '$3 == uid { print $1 }' /etc/passwd`
if [ 0$old_user_name != 0 ]; then
    printf "$0: UID $new_uid is in use by user $old_user_name.\n"
    exit 1
fi

if [ 0$silent != 01 ]; then
    printf "Changing user $user_name from $old_uid to $new_uid.\n"

    cat << EOM

Files owned by user $old_uid will be updated to $new_uid under the
following directories:

    $dirs

EOM

    if [ $dirs != / ]; then
	cat << EOM
Files in other directories will retain ownership $old_uid and will
have to be fixed manually.

EOM
    fi
    printf "Finding and updating all files could take a very long time.\n"
    printf "Are you sure you want to continue? yes/[no] "
    read continue
    if [ 0$continue != 0yes ]; then
	exit 0
    fi
fi

case $(auto-ostype) in
Darwin)
    dscl . -change /Users/$user_name UniqueID $old_uid $new_uid
    ;;

FreeBSD)
    pw usermod $user_name -u $new_uid
    ;;

NetBSD|RHEL)
    usermod -u $new_uid $user_name
    ;;

*)
    auto-unsupported-os $0
    exit 1
    ;;
esac

# Fix ownership of files in specified directories
if [ 0"$dirs" != 0 ]; then
    find $dirs -fstype nfs -prune -o \
	-user $old_uid -exec chown $verbose -h $user_name '{}' +
fi
