Last active
December 30, 2023 19:38
-
-
Save tgran2028/4f5807e22c7b60e1cda5e32aa0ea46b3 to your computer and use it in GitHub Desktop.
Util to copy file/dir from one user to another. This includes parsing relative paths to a user's home, updating ownership, and modifying file contents to home path changes (e.g. /home/foo -> /home/bar).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env bash | |
set -e | |
set -o pipefail | |
display_help() { | |
echo "Usage: cp-from-user [option...] --path <PATH> --source-user <SRC-USER> [--destination-user <DST-USER>]" | |
echo | |
echo "Util to copy file or directory from one user to another" | |
echo | |
echo " -p, --path <PATH> Path to the file or directory from home directory." | |
echo " Accepts both relative path and a relative path to" | |
echo " the src user's home directory" | |
echo " -s, --source-user <SRC-USER> Source user from which to copy the file or directory" | |
echo " -d, --destination-user <DST-USER> Destination user to which to copy the file or" | |
echo " directory. Defaults to current user" | |
echo " -h, --help Display help messages" | |
exit 0 | |
} | |
cp_from_user() { | |
local path_rel_to_home | |
local src_user | |
local dst_user | |
while [ "$#" -gt 0 ]; do | |
case "$1" in | |
-p | --path) | |
path_rel_to_home="$2" | |
shift 2 | |
;; | |
-s | --source-user) | |
src_user="$2" | |
shift 2 | |
;; | |
-d | --destination-user) | |
dst_user="$2" | |
shift 2 | |
;; | |
-h | --help) | |
display_help | |
;; | |
--) # end argument parsing | |
shift | |
break | |
;; | |
-*) | |
echo "Error: Unsupported flag $1" >&2 | |
exit 1 | |
;; | |
*) # preserve positional arguments | |
PARAMS="$PARAMS $1" | |
shift | |
;; | |
esac | |
done | |
# set positional arguments in their proper place | |
eval set -- "$PARAMS" | |
if [ -z "$path_rel_to_home" ]; then | |
echo "Error: path must be provided" | |
exit 1 | |
fi | |
if [ -z "$src_user" ]; then | |
# check if path_rel_to_home is provided contains /root or /home/<user> | |
# if /root, set src_user to root | |
if [ "${path_rel_to_home:0:5}" == "/root" ]; then | |
src_user="root" | |
# if /home/<user>, set src_user to <user> | |
elif [[ "${path_rel_to_home:0:6}" == "/home/"* ]]; then | |
src_user="${path_rel_to_home:6}" | |
src_user="${src_user%%/*}" | |
else | |
echo "Error: source user must be provided" | |
exit 1 | |
fi | |
fi | |
# set default value for dst_user if not provided | |
[ -z "$dst_user" ] && dst_user="$(whoami)" | |
local src_home | |
local src | |
# dst | |
local dst_home | |
local dst | |
# check if root or not root for $2. If not root, set src_home to /home/$2 else set src_home to /root | |
if [ "$src_user" != "root" ]; then | |
src_home="/home/$src_user" | |
if [ ! -d "$src_home" ]; then | |
echo "Error: $src_home does not exist" | |
exit 1 | |
fi | |
else | |
src_home="/root" | |
fi | |
if [ "$dst_user" != "root" ]; then | |
dst_home="/home/$dst_user" | |
if [ ! -d "$dst_home" ]; then | |
echo "Error: $dst_user does not exist" | |
exit 1 | |
fi | |
else | |
dst_home="/root" | |
fi | |
if [[ "$src_user" == "$dst_user" ]]; then | |
echo "source and current users are the same." | |
exit 1 | |
fi | |
# remove src_home from path_rel_to_home | |
path_rel_to_home="${path_rel_to_home#"${src_home}"/}" | |
src="$src_home/$path_rel_to_home" | |
dst="$dst_home/$path_rel_to_home" | |
# remove // from both src and dst (possible artifact from joining vars) | |
src="${src//\/\//\/}" | |
dst="${dst//\/\//\/}" | |
# remove dst if exits, but with user confirmation | |
if [ -e "$dst" ]; then | |
read -p "Do you want to remove $dst? [y/N] " -n 1 -r | |
echo | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
rm -rf "$dst" | |
else | |
echo "Aborted" | |
exit 1 | |
fi | |
fi | |
echo -e '\n-------------------------------------------------' | |
echo "SOURCE USER: $src_user" | |
echo "SOURCE FILE: '$src'" | |
echo "DEST. USER: $dst_user" | |
echo "DEST. FILE: '$dst'" | |
echo -e '-------------------------------------------------\n' | |
# check if src exist (either file or directory) | |
if [ ! -e "$src" ]; then | |
echo "Error: $src does not exist" | |
exit 1 | |
fi | |
mkdir -p "$(dirname "$dst")" >/dev/null 2>&1 | |
if [ -d "$src" ]; then | |
# if src is a directory, copy recursively | |
cp -rvf "$src" "$dst" | |
# change group and/or user ownership inline with original file | |
chown -R "$(stat -c "%U:%G" "$src")//$src_user/$dst_user" "$dst" | |
# iterate through files and ensure all old $HOME paths are replaced with the current user | |
for i in $(find "$dst" -type f); do | |
sed i "s|$src_home|$dst_home|g" "$i" > /dev/null 2>&1 | |
done | |
else | |
# if src is a file, copy | |
cp -vf "$src" "$dst" | |
# fix ownership | |
chown "$(stat -c "%U:%G" "$src")//${src_user}/${dst_user}" "$dst" | |
# fix home path | |
sed i "s|$src_home|$dst_home|g" "$dst" > /dev/null 2>&1 | |
fi | |
exit 0 | |
} | |
### main ### | |
# help if no args or -h or --help is passed | |
if [[ $# -eq 0 ]] || [[ "$*" == *"-h"* ]] || [[ "$*" == *"--help"* ]]; then | |
display_help | |
fi | |
cp_from_user "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment