mirror of
https://github.com/erenfro/gen2stage4.git
synced 2024-11-24 07:15:34 -05:00
216 lines
5.3 KiB
Bash
Executable file
216 lines
5.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# set flag variables to null/default
|
|
optExcludeBoot=false
|
|
optExcludeConfidential=false
|
|
optExcludeLost=true
|
|
optQuiet=false
|
|
optUserExclude=()
|
|
|
|
|
|
function showHelp() {
|
|
echo "Usage:"
|
|
echo "$(basename "$0") [-b -c -l -q] [-s || -t <target>] [-e <exclude>...] [-i <include>...] <dest> [-- [rsync-opts]]"
|
|
echo "Position Arguments:"
|
|
echo " <dest> destination path to copy system files to"
|
|
echo " [rsync-opts] additional options to pass to rsync command"
|
|
echo
|
|
echo "Options:"
|
|
echo " -b excludes boot directory"
|
|
echo " -c excludes some confidential files (currently only .bash_history and connman network lists)"
|
|
echo " -l includes lost+found directory"
|
|
echo " -q activates quiet mode (no confirmation)"
|
|
echo " -s makes copy of current system"
|
|
echo " -t <path> makes copy of system located at the <path>"
|
|
echo " -e <exclude> an additional exclude directory (one dir one -e, do not use it with *)"
|
|
echo " -i <include> an additional include. This has higher precedence than -e, -t, and -s"
|
|
echo " -h display this help message."
|
|
|
|
if [[ "$1" -ge 0 ]]; then
|
|
exit "$1"
|
|
else
|
|
exit 0
|
|
fi
|
|
}
|
|
|
|
function errorMsg() {
|
|
local rc=0
|
|
|
|
if [[ "$1" -gt 0 ]]; then
|
|
rc="$1"
|
|
shift
|
|
fi
|
|
|
|
echo "$*" >&2
|
|
|
|
if [[ "$rc" -gt 0 ]]; then
|
|
exit "$rc"
|
|
fi
|
|
}
|
|
|
|
|
|
# reads options:
|
|
while [[ $# -gt 0 ]]; do
|
|
while getopts ":t:e:i:sqcblh" flag; do
|
|
case "$flag" in
|
|
t) sourcePath="$OPTARG";;
|
|
s) sourcePath="/";;
|
|
q) optQuiet=true;;
|
|
c) optExcludeConfidential=true;;
|
|
b) optExcludeBoot=true;;
|
|
l) optExcludeLost=false;;
|
|
e) optUserExclude+=("$OPTARG");;
|
|
i) optUserInclude+=("$OPTARG");;
|
|
h) showHelp 0;;
|
|
\?) errorMsg 1 "Invalid option: -$OPTARG";;
|
|
:) errorMsg 1 "Option -$OPTARG requires an argument.";;
|
|
esac
|
|
done || exit 1
|
|
|
|
[[ $OPTIND -gt $# ]] && break # reached the end of parameters
|
|
|
|
shift $((OPTIND - 1)) # Free processed options so far
|
|
OPTIND=1 # we must reset OPTIND
|
|
if [[ -z "$targetPath" ]]; then
|
|
targetPath=$1
|
|
else
|
|
rsyncArgs[${#rsyncArgs[*]}]=$1
|
|
fi
|
|
shift # remove saved arg
|
|
done
|
|
|
|
|
|
# checks if run as root:
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|
echo "$(basename "$0"): must run as root"
|
|
exit 250
|
|
fi
|
|
|
|
if [[ -z "$sourcePath" ]]; then
|
|
echo "$(basename "$0"): no source path specified"
|
|
exit 1
|
|
elif [[ ! -d "$sourcePath" ]]; then
|
|
echo "$(basename "$0"): no source path does not exist"
|
|
exit 1
|
|
elif [[ "$sourcePath" != */ ]]; then
|
|
# make sure source path ends with slash
|
|
sourcePath="${sourcePath}/"
|
|
fi
|
|
|
|
if [[ -z "$targetPath" ]]; then
|
|
echo "$(basename "$0"): no destination path specified"
|
|
exit 1
|
|
elif [[ ! -d "$targetPath" ]]; then
|
|
echo "$(basename "$0"): destination path (\`$targetPath\`) does not exist"
|
|
exit 1
|
|
elif [[ "$targetPath" != */ ]]; then
|
|
# make sure destination path ends with slash
|
|
targetPath="${targetPath}/"
|
|
fi
|
|
|
|
# Excludes:
|
|
syncExcludes=(
|
|
"dev/*"
|
|
"var/tmp/*"
|
|
"media/*"
|
|
"mnt/*/*"
|
|
"proc/*"
|
|
"run/*"
|
|
"sys/*"
|
|
"tmp/*"
|
|
"var/lock/*"
|
|
"var/log/*"
|
|
"var/run/*"
|
|
"var/lib/docker/*"
|
|
"var/lib/containers/*"
|
|
"var/lib/machines/*"
|
|
"var/lib/libvirt/*"
|
|
"var/lib/lxd/*"
|
|
"home/*/*"
|
|
)
|
|
|
|
#EXCLUDES_DEFAULT_PORTAGE=(
|
|
syncExcludesPortage=(
|
|
"var/db/repos/*/*"
|
|
"var/cache/distfiles/*"
|
|
"var/cache/binpkgs/*"
|
|
"usr/portage/*"
|
|
)
|
|
|
|
syncIncludes=(
|
|
"dev/console"
|
|
"dev/null"
|
|
"var/db/pkg/*"
|
|
)
|
|
|
|
syncExcludes=("${syncExcludes[@]/#/"$sourcePath"}")
|
|
syncIncludes=("${syncIncludes[@]/#/"$sourcePath"}")
|
|
|
|
if [[ "$sourcePath" == '/' ]]; then
|
|
if command -v portageq &>/dev/null; then
|
|
portageRepos=$(portageq get_repos /)
|
|
for i in ${portageRepos}; do
|
|
repoPath=$(portageq get_repo_path / "${i}")
|
|
syncExcludes+=("${repoPath}/*")
|
|
done
|
|
syncExcludes+=("$(portageq distdir)/*")
|
|
syncExcludes+=("$(portageq pkgdir)/*")
|
|
else
|
|
syncExcludes+=("${syncExcludesPortage[@]/#/"/"}")
|
|
fi
|
|
else
|
|
syncExcludes+=("${syncExcludesPortage[@]/#/"$sourcePath"}")
|
|
fi
|
|
|
|
if $optExcludeConfidential; then
|
|
syncExcludes+=("${sourcePath}home/*/.bash_history")
|
|
syncExcludes+=("${sourcePath}root/.bash_history")
|
|
syncExcludes+=("${sourcePath}var/lib/connman/*")
|
|
fi
|
|
|
|
if $optExcludeBoot; then
|
|
syncExcludes+=("${sourcePath}boot/*")
|
|
fi
|
|
|
|
if $optExcludeLost; then
|
|
syncExcludes+=("lost+found")
|
|
fi
|
|
|
|
syncExcludes+=("${optUserExclude[@]}")
|
|
syncIncludes+=("${optUserInclude[@]}")
|
|
|
|
# Generic rsync options:
|
|
rsyncOptions=(
|
|
-avxHAXS
|
|
--numeric-ids
|
|
"--info=progress2"
|
|
)
|
|
|
|
rsyncOptions+=("${rsyncArgs[@]}")
|
|
|
|
# if not in quiet mode, this message will be displayed:
|
|
if ! $optQuiet; then
|
|
echo "Are you sure that you want to copy system files located under"
|
|
echo "$sourcePath"
|
|
echo "to the following directory"
|
|
echo "$targetPath"
|
|
echo
|
|
echo "WARNING: since all data is copied by default the user should exclude all"
|
|
echo "security- or privacy-related files and directories, which are not"
|
|
echo "already excluded, manually per cmdline."
|
|
echo "example: \$ $(basename "$0") -s -e \"/etc/ssh/ssh_host*\" <destination>"
|
|
echo
|
|
echo "COMMAND LINE PREVIEW:"
|
|
echo 'rsync' "${rsyncOptions[@]}" "${syncIncludes[@]/#/--include=}" "${syncExcludes[@]/#/--exclude=}" "$sourcePath" "$targetPath"
|
|
echo
|
|
echo -n 'Type "yes" to continue or anything else to quit: '
|
|
read -r promptAgree
|
|
if [[ "${promptAgree,,}" == "yes" ]]; then
|
|
optQuiet=true
|
|
fi
|
|
fi
|
|
|
|
# start stage4 creation:
|
|
if $optQuiet; then
|
|
rsync "${rsyncOptions[@]}" "${syncExcludes[@]/#/--exclude=}" "$sourcePath" "$targetPath"
|
|
fi
|