#!/bin/bash # I, Ian Kelling, follow the GNU license recommendations at # https://www.gnu.org/licenses/license-recommendations.en.html. They # recommend that small programs, < 300 lines, be licensed under the # Apache License 2.0. This file contains or is part of one or more small # programs. If a small program grows beyond 300 lines, I plan to switch # its license to GPL. # Copyright 2024 Ian Kelling # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. source /a/bin/bash-bear-trap/bash-bear err-cleanup() { echo 1 >~/.local/conflink } usage() { cat <&2; exit 1; } fast=false verbose=false temp=$(getopt -l help hvf "$@") || usage 1 eval set -- "$temp" while true; do case $1 in -v) verbose=true ;; -f) fast=true ;; -h|--help) usage ;; --) shift; break ;; *) echo "$0: unexpected args: $*" >&2 ; usage 1 ;; esac shift done readonly fast verbose ##### end command line parsing ######## tmpf=$(mktemp) if $fast; then lnf() { ln -sf "$@"; } fi if $verbose; then m() { echo "$*" "$@" } fi shopt -s nullglob shopt -s extglob shopt -s dotglob # If we make a link back to the root, we stop going deeper into subdir_files. # This makes it so we can do subdir directories. eg # /p/c/subdir_files/.config/gajim -> ../../gagim # # Also note, under filesystem/, symlinks are expanded. subdir-link-r() { local root="$1" local targets=() if [[ $2 ]]; then targets=( "$2"/!(.git|..|.|.#*) ) else for f in "$1"/!(.git|..|.|.#*); do if [[ -d $f ]]; then targets+=("$f"); fi done fi local below below="$( readlink -f "$root/..")" for path in "${targets[@]}"; do local fullpath fullpath="$(readlink -f "$path")" if [[ -f $path || $(dirname "$fullpath") == "$below" ]]; then m lnf -T "$path" "$HOME/${path#"$root/"}" elif [[ -d "$path" ]]; then subdir-link-r "$root" "$path" fi done } common-file-setup() { local dir fs x f reload_systemd local -a restart_services reload_systemd=false # note, i ran chmod -R g-s on the filesystem dirs # so i could keep permissions of secret files for dir in "$@"; do fs=$dir/filesystem if [[ -e $fs && $user =~ ^iank?$ ]]; then # we dont want t, instead c for checksum. # That way we dont set times on directories. # -a = -rlptgoD # -A is acls, implies -p cmd=( s rsync -rclgoDiSAX --chmod=Dg-s --chown=root:root --exclude=/etc/dovecot/users --exclude='/etc/exim4/passwd*' --exclude='/etc/exim4/*.pem' $fs/ / ) echo "${cmd[@]@Q}" "${cmd[@]}" | tee $tmpf while read -r line; do file="${line:12}" case $file in etc/prometheus/rules/iank.yml|etc/prometheus/prometheus.yml) case $HOSTNAME in kd) if systemctl is-active prometheus &>/dev/null; then v s systemctl reload prometheus fi ;; esac ;; etc/systemd/system/*) reload_systemd=true ;; etc/dnsmasq.d/*) restart_services+=(dnsmasq) ;; etc/systemd/resolved.conf.d/*) restart_services+=(systemd-resolved) ;; esac # Previously did this with tar, but it doesn't # update directory permissions. # # S = do spare files efficiently # A = preserve acls # X = preserve extended attributes # i = itemize done <$tmpf fi if ! $fast && [[ -e $dir/subdir_files ]]; then m subdir-link-r $dir/subdir_files fi local x=( $dir/!(binds|subdir_files|filesystem|machine_specific|..|.|.#*) ) (( ${#x[@]} >= 1 )) || continue m lnf ${x[@]} ~ done if $reload_systemd; then v s systemctl daemon-reload fi for service in ${restart_services[@]}; do if systemctl is-active $service >/dev/null; then v s systemctl restart $service fi done } user=$(id -un) all_dirs=({/a/bin/ds,/p/c}{,/machine_specific/$HOSTNAME}) # note, we assume a group of hosts does not have the # same name as a single host, which is no problem on our scale. for x in /p/c/machine_specific/*.hosts /a/bin/ds/machine_specific/*.hosts; do if grep -qxF $HOSTNAME $x; then all_dirs+=( ${x%.hosts} ); fi done c_dirs=(/a/c{,/machine_specific/$HOSTNAME}) case $user in iank) # old files 2022-03 for t in systemstatus epanicclean btrfsmaintstop dynamicipupdate; do f=/etc/systemd/system/$t.timer if [[ -e $f ]]; then v systemctl stop $t.timer v systemctl disable $t.timer s rm -fv $f reload_systemd=true fi done # old 2022-04 if [[ -e /etc/cron.daily/check-lets-encrypt-ssl-settings ]]; then m s rm -f /etc/cron.daily/check-lets-encrypt-ssl-settings fi # conversion from whole folder subdir to individual files. if [[ -L /home/iank/.config/copyq ]]; then rm -fv /home/iank/.config/copyq fi /a/bin/ds/install-my-scripts files=(/p/c/machine_specific/*/filesystem/etc/ssh/*_key /p/c/machine_specific/*/filesystem/etc/openvpn/client/*.key /p/c/filesystem/etc/openvpn/client/*.key /p/c/filesystem/etc/openvpn/easy-rsa/keys/*.key ) if [[ -e ${files[0]} ]]; then chmod 600 ${files[@]} fi # p needs to go first so .ssh link is created, then config link inside it m common-file-setup ${all_dirs[@]} #### begin special extra stuff #### install -d -m700 ~/gpg-agent-socket f=/var/lib/bind if [[ -e $f ]]; then # reset to the original permissions. m s chgrp -R bind $f m s chmod g+w $f fi # shellcheck disable=SC2016 # obviously expected s bash -c 'shopt -s nullglob; for f in /etc/bind/*.key /etc/bind/*.private /etc/bind/key.*; do chgrp bind $f; done' if [[ -e /etc/caldav-htpasswd ]] && getent group www-data &>/dev/null; then s chgrp www-data /etc/caldav-htpasswd fi if [[ -e /var/lib/znc ]] && getent group znc; then s chown -R znc:znc /var/lib/znc fi if [[ -e /p/c/user-specific ]]; then if getent passwd prometheus &>/dev/null; then v s rsync -clpgoDiSAX --chmod=Dg-s --chown=root:prometheus /p/c/user-specific/prometheus/prometheus-pass /etc v s rsync -clpgoDiSAX --chmod=Dg-s --chown=root:prometheus /p/c/user-specific/prometheus/prometheus/ssl/* /etc/prometheus/ssl fi if getent passwd www-data &>/dev/null; then v s rsync -clpgoDiSAX --chmod=Dg-s --chown=root:www-data /p/c/user-specific/www-data/* /etc fi fi if [[ -d /var/lib/bitcoind && -d /p/c/user-specific/bitcoin ]]; then s rsync -clpgoDiSAX --chmod=Dg-s --chown=bitcoin:bitcoin /p/c/user-specific/bitcoin/settings.json /var/lib/bitcoind s rsync -rclpgoDiSAX --chmod=Dg-s --chown=root:bitcoin /p/c/user-specific/bitcoin/bitcoin /etc fi # this folder strangely requires ownership as icecast2 if [[ -d /etc/icecast2 && -f /p/c/icecast.xml ]]; then m s rsync -rclgoDiSAX --chmod=0644 --chown=root:root /p/c/icecast.xml /etc/icecast2 fi ##### end special extra stuff ##### if ! $fast; then m s -H -u user2 "${BASH_SOURCE[0]}" fi f=/a/bin/distro-setup/system-status if [[ -x $f ]]; then $f _ fi mkdir -p ~/.local echo 0 >~/.local/conflink ;; user2) m common-file-setup ${c_dirs[@]} ;; *) echo "$0: error: unexpected user"; exit 1 ;; esac