Files
spark/docker/sparkd/dev/set_user.sh
T
John Colvin 2bf4502d06 docker: Add set_user/start_docker scripts
Leave the image's default user as 'root' so we can modify the non-root user's
uid/gid. This is a common technique used in containers to gain file permissions
in mounted dirs.

The default user's uid/gid can't be changed because a bash process runs under
their ownership as long as the container is up. A user's uid/gid cannot be
changed while that user owns a process (at least not via 'usermod').
2023-04-04 23:52:10 -04:00

251 lines
6.5 KiB
Bash
Executable File

#!/usr/bin/env bash
function _exit() {
if [[ "$#" -gt 1 ]]; then
# When there are multiple args, the last arg is the exit code.
echo "${@:1:($# - 1)}"
exit "${@: -1}"
fi
echo "$1"
exit 0
}
help_text="\
Add or update a user's uid
This script is intended to be run in a Docker container as a means to obtain
file permissions in mounted directories owned by the specified UID.
Usage: set_user.sh [OPTIONS] USER UID
Positionals:
USER The name of the user
Options:
--user USER The name of the user (defaults to 'bts')
--uid UID The new uid to give USER (defaults to '1000')
--group GROUP The primary group to give USER (defaults to USER)
--gid GID The primary gid to give USER (defaults to UID)
--pass PASSWORD The password to give USER (defaults to USER, only applies
if USER hasn't been created yet)
--modify-existing Update UID/GID even if USER already exists
-h,--help Print this help message and exit
"
function _add_group() {
if [[ "$#" -ne 2 ]]; then
_exit "'_add_group' requires exactly 2 args (group, gid). Received $#." 1
fi
local group="$1"
local gid="$2"
# Check if gid already exists
local existing_group=""
existing_group="$(getent group "$gid" | cut -d : -f 1)"
if [[ -n "$existing_group" ]]; then
if [[ "$existing_group" != "$group" ]]; then
echo "\
The gid '$gid' is already in use by group '$existing_group' (will not rename \
the group)"
fi
return
fi
# Check if group with same name already exists
local existing_gid=""
existing_gid="$(getent group "$group" | cut -d : -f 3)"
if [[ -n "$existing_gid" ]]; then
# The group already exists. Only modify if --modify-existing was specified.
if [[ "$modify_existing" -eq 0 ]]; then
_exit "\
The group '$group' already exists with gid '$existing_gid'.
Specify --modify-existing to change the gid anyways." 1
fi
echo "Changing gid for group '$group' from '$existing_gid' to '$gid'"
groupmod -g "$gid" "$group"
else
# The group doesn't exist. Add it
echo "Adding group '$group:$gid'"
groupadd -g "$gid" "$group"
fi
}
function _add_user() {
local user="$1"
local uid="$2"
local group="$3"
local gid="$4"
local pass="$5"
if [[ "$#" -ne 5 ]]; then
_exit "'_add_user' requires exactly 5 args (user, uid, group, gid, pass). \
Received $#." 1
fi
# Check if uid is being used by another user
local existing_user=""
existing_user="$(getent passwd "$uid" | cut -d : -f 1)"
if [[ -n "$existing_user" ]]; then
if [[ "$existing_user" != "$user" ]]; then
_exit "The uid '$uid' is already in use by user '$existing_user'." 1
fi
echo "The user '$user' already has the specified uid '$uid'."
# Modify gid if necessary
local existing_gid=""
existing_gid="$(id -g "$user" 2> /dev/null)"
if [[ "$existing_gid" = "$gid" ]]; then
echo "The user '$user' already has the specified gid '$gid'."
return
fi
if [[ "$modify_existing" -eq 0 ]]; then
_exit "\
The user '$user' is associated with the primary group '$existing_gid'.
Specify --modify-existing to change the gid anyways." 1
fi
echo "Changing primary group for '$user' from '$existing_gid' to '$gid'."
usermod -g "$gid" "$user"
return
fi
# Check if user with same name already exists
local existing_uid=""
existing_uid="$(id -u "$user" 2> /dev/null)"
if [[ -n "$existing_uid" ]]; then
if [[ "$existing_uid" = "$uid" ]]; then
_exit "The user '$user' already has the specified uid '$uid'" 0
fi
if [[ "$modify_existing" -eq 0 ]]; then
_exit "\
User '$user' already exists with uid '$existing_uid'.
Specify --modify-existing to change the uid anyways." 1
fi
echo "Changing uid for user '$user' from '$existing_uid' to '$uid'"
if ! usermod -u "$uid" -g "$gid" "$user"; then
_exit "usermod exited with code $?" 1
fi
return
fi
# The user doesn't exist. Add it
echo "Adding user '$user:$uid' (group='$group:$gid', password='$pass')"
useradd -m -u "$uid" -g "$gid" -G sudo --password "$(openssl passwd -1 "$pass")" "$user"
}
function _update_fish_dir_perms() {
local user="$1"
local uid="$2"
local gid="$3"
# When a fish shell session starts, a temp dir named '/tmp/fish.<user>' is
# created with the user's current uid/gid. If such a dir exists for the
# specified USER, make sure the uid/gid match the new values.
fish_dir="/tmp/fish.$user"
if [[ -d "$fish_dir" ]]; then
perms="$uid:$gid"
existing_perms="$(stat -c %u:%g "$fish_dir")"
if [[ "$existing_perms" != "$perms" ]]; then
echo "Changing uid:gid for dir '$fish_dir' from '$existing_perms' to '$perms'"
chown -R "$perms" "$fish_dir"
fi
fi
}
user=""
group=""
pass=""
declare -i uid=0
declare -i gid=0
declare -i modify_existing=0
while [[ $# -gt 0 ]]; do
case "$1" in
--user)
if [[ -z "$2" ]]; then
_exit "USER (--user) must be non-empty" 1
elif [[ "$2" = "root" ]]; then
_exit "USER (--user) cannot be 'root'" 1
fi
user="$2"
shift 2
;;
--group)
if [[ -z "$2" ]]; then
_exit "GROUP (--group) must be non-empty" 1
elif [[ "$2" = "root" ]]; then
_exit "GROUP (--group) cannot be 'root'" 1
fi
group="$2"
shift 2
;;
--uid)
if [[ -z "$2" ]]; then
_exit "UID (--uid) must be non-empty" 1
fi
uid="$2"
shift 2
;;
--gid)
if [[ -z "$2" ]]; then
_exit "GID (--gid) must be non-empty" 1
fi
gid="$2"
shift 2
;;
--pass)
if [[ -z "$2" ]]; then
_exit "PASS (--pass) must be non-empty" 1
fi
pass="$2"
shift 2
;;
--modify-existing)
modify_existing=1
shift 1
;;
-h)
;&
--help)
_exit "$help_text" 0
;;
*)
if [[ -z "$1" ]]; then
_exit "Invalid positional argument '$1'" 1
elif [[ -z "$user" ]]; then
user="$1"
elif [[ -z "$uid" ]]; then
uid="$1"
else
_exit "Unexpected argument '$1'" 1
fi
shift 1
;;
esac
done
if [[ -z "$user" ]]; then
user="bts"
fi
if [[ $uid -eq 0 ]]; then
uid=1000
fi
# In general, a user's primary group/gid matches the user's name/uid.
# If group/gid args weren't specified, set them to name/uid.
if [[ -z "$group" ]]; then
group="$user"
fi
if [[ $gid -eq 0 ]]; then
gid=$uid
fi
if [[ -z "$pass" ]]; then
pass="$user"
fi
_add_group "$group" "$gid"
_add_user "$user" "$uid" "$group" "$gid" "$pass"
_update_fish_dir_perms "$user" "$uid" "$gid"