# Gets all the essential disk info on a machine. In case it gets ill, this
# will help us know the expected state.
disk-info() {
- local cmds cmd
+ local cmds cmd cmd_name
mapfile -t cmds <<'EOF'
tail -n +1 /proc/mdstat /etc/mdadm/mdadm.conf /etc/fstab /etc/crypttab
lsblk
EOF
for cmd in "${cmds[@]}"; do
+ cmd_name="${cmd%% *}"
+ command -p $cmd_name &>/dev/null || continue # we dont have btrfs on some old hosts
cat <<EOF
### $cmd
#### end fsf section
+sl-local-test() {
+ remote="$1"
+ if [[ $remote == *.fsf.org ||
+ $remote == *.gnu.org ||
+ $remote == *.libreplanet.org ]]; then
+ e sync
+ elif [[ $remote == *.b8.nz ]]; then
+ e skip
+ fi
+}
+export SL_LOCAL_TEST_CMD=sl-local-test
..() { c ..; }
...() { c ../..; }
done
}
+# sets $host_type, and maybe some related vars: $pre_synced, $extra_info
+_sl-get-host-type() {
+ local tmp tmp2 testbool testcmd
+ local -a tmpa
+ if [[ $sl_local_test_cmd ]]; then
+ host_type=$($sl_local_test_cmd "$remote")
+ fi
+ if [[ $host_type ]]; then return; fi
-#### sl: ssh wrapper, but maybe first rsync files that we configure and
+ tmpa=($SL_INFO_DIR/??????????-????-"$remote")
+ sshinfo=${tmpa[0]}
+ if [[ -e $sshinfo ]]; then
+ tmp=${sshinfo[0]##*/}
+ tmp2=${tmp:11} # skip 11 chars
+ host_type=${tmp2%%-*}
+ extra_info=$(cat $sshinfo)
+
+ ### block to see if past sync is up to date
+ if $force_rsync; then return; fi
+ info_sec=${tmp::10}
+ read -r files_sec _ < <(find -L $SL_FILES_DIR -printf "%T@ %p\n" | sort -nr || [[ $? == 141 || ${PIPESTATUS[0]} == 32 ]] )
+ files_sec=${files_sec%%.*}
+ # info_sec is the last time we synced to that host. files_sec is the
+ # greatest mod time out of files we want to sync.
+ if (( files_sec <= info_sec )); then
+ pre_synced=true
+ fi
+ return
+ fi
+
+ # we test for string to know ssh succeeded
+ testbool="test -e $SL_FILES_DIR/.bashrc -a -L .bashrc -a -v LC_USEBASHRC"
+ testcmd="if $testbool; then printf y; else printf n; fi"
+ if ! tmp=$(mq LC_USEBASHRC=t command ssh "${args[@]}" "$remote" "$testcmd; $sl_test_cmd"); then
+ echo failed sl test. doing plain ssh -v
+ command ssh -v "${args[@]}" "$remote"
+ fi
+ if [[ $tmp == y* ]]; then # y = yes test result
+ host_type=skip
+ else
+ host_type=sync
+ fi
+ extra_info="${tmp:1}"
+}
+
+
+#### sl: ssh wrapper, but if needed, first rsync files that we configure and
# always source our .bashrc on the remote.
-# TODO: this needs better documentation.
+# TODO: docs needs polishing.
# Usage: all the same args as ssh + a few below. Note, combining options
# that have arguments with ones that dont, like -4oOption is not
# is that the ssh target does not have files we previously rsynced for
# various reasons. I have a wrapper for this called slr below.
+# SL_LOCAL_TEST_CMD / --sl-local-test-cmd: Env var or cli option. If
+# set, we run this command with the remote host as an argument and if
+# its output is "sync" we do rsync. If it is "skip", we don't
+# rsync. Otherwise, we carry on. This will avoid the ssh done for
+# new hosts to discover if SL_FILES_DIR exists, which can be convenient.
+
# SL_TEST_CMD / --sl-test-cmd CMD: Env var or cli option. If set, we run
# this string on the remote host the first time sl is run (or if we run
# slr). Its standard out is passed to SL_TEST_HOOK which gets run
# SL_SSH_ARGS: Env var. Default arguments passed to ssh.
-# For when ~/.bashrc is already customized on the remote server, you
-# might find it problematic that ~/.bashrc is sourced for ALL ssh
-# commands, even in scripts. This paragraph is all about that. bash
-# scripts dont source ~/.bashrc, but call ssh in scripts and you get
-# ~/.bashrc. You dont want this. .bashrc is meant for interactive shells
-# and if you customize it, probably has bugs from time to time. This is
-# bad. Here's how I fix it. I have a special condition to "return" in my
-# .bashrc for noninteractive ssh shells (copy that code). Then use this
-# function or similar that passes LC_USEBASHRC=t when sshing and I want
-# my bashrc. Also, I don't keep most of my bashrc in .bashrc, i source a
-# separate file because even if I return early on, the whole file gets
-# parsed which can fail if there is a syntax error.
+# When ~/.bashrc is already customized on the remote server, you might
+# find it problematic that ~/.bashrc is sourced for ALL ssh commands,
+# even in scripts. This paragraph is all about that. bash scripts dont
+# source ~/.bashrc, but call ssh in scripts and you get ~/.bashrc. You
+# dont want this. .bashrc is meant for interactive shells and bugs in it
+# should be limited to that. This is a bad default. I created a
+# workaround so that .bashrc is unused by default in ssh then I opt-in
+# for interactive ssh. The mechanism is: I have a condition to "return"
+# in my .bashrc if under ssh and the variable LC_USEBASHRC=t is not
+# set. Then, when sshing interactively, I use an ssh wrapper which sets
+# that variable. Also, I don't keep most of my bashrc in .bashrc, i
+# source a separate file because even if I return early on, the whole
+# file gets parsed which can fail if there is a syntax error.
sl() {
# Background on LC_USEBASHRC var (no need to read if you just want to
# use this function): env variables sent across ssh are strictly
# .bashrc. This means the outer shell still ran the default .bashrc,
# but that is the best we can do.
- local verbose now args remote do_rsync haveinfo tmpa sshinfo tmp tmp2 host_type info_sec force_rsync
- local sync_dirname testcmd extra_info testbool files_sec sl_test_cmd sl_test_hook
- local sl_rsync_cmd sl_test_cmd sl_test_hook
- declare -a args tmpa
+ local verbose now args remote sshinfo tmp host_type info_sec force_rsync
+ local sync_dirname extra_info files_sec sl_test_cmd sl_test_hook pre_synced
+ local sl_rsync_cmd sl_test_cmd sl_test_hook sl_local_test_cmd
+ local -a args
args=($SL_SSH_ARGS)
# [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]
# [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]
- # shellcheck disable=SC3127 # todo: remove this once we use this var
verbose=false
force_rsync=false
if [[ $1 == --rsync ]]; then
shift
fi
# shellcheck disable=SC2153 # intentional
+ sl_local_test_cmd=$SL_LOCAL_TEST_CMD
+ # shellcheck disable=SC2153 # intentional
sl_test_cmd=$SL_TEST_CMD
# shellcheck disable=SC2153 # intentional
sl_test_hook=$SL_TEST_HOOK
--rsync)
force_rsync=true
;;
+ --sl-local-test-cmd)
+ sl_local_test_cmd="$2"
+ shift
+ ;;
--sl-test-cmd)
sl_test_cmd="$2"
shift
case "$1" in
# note we dont support things like -4oOption
-[46AaCfGgKkMNnqsTtVvXxYy]*)
+
if [[ $1 == *v* ]]; then
- # todo: try running slowdo if this is false
- # shellcheck disable=SC2034 # todo: remove this once we use this var
+ # used by mq etc
verbose=true
fi
+
args+=("$1"); shift
;;
-[bcDEeFIiJLlmOopQRSWw]*)
return 1
fi
- do_rsync=false
- haveinfo=false
- tmpa=($SL_INFO_DIR/??????????-????-"$remote")
- sshinfo=${tmpa[0]}
- if [[ -e $sshinfo ]]; then
- if $force_rsync; then
- rm -f $sshinfo
- else
- haveinfo=true
- fi
- fi
- if $haveinfo; then
- tmp=${sshinfo[0]##*/}
- tmp2=${tmp:11} # skip 11 chars
- host_type=${tmp2%%-*}
- extra_info=$(cat $sshinfo)
- # debug
- #echo d1 $host_type
- else
- # we test for string to know ssh succeeded
- testbool="test -e $SL_FILES_DIR/.bashrc -a -L .bashrc -a -v LC_USEBASHRC"
- testcmd="if $testbool; then printf y; else printf n; fi"
- if ! tmp=$(mq LC_USEBASHRC=y command ssh "${args[@]}" "$remote" "$testcmd; $sl_test_cmd"); then
- echo failed sl test. doing plain ssh -v
- command ssh -v "${args[@]}" "$remote"
- fi
- if [[ $tmp == y* ]]; then
- # yes test result, no need to rsync this host.
- host_type=skip
- else
- do_rsync=true
- host_type=sync
- fi
- extra_info="${tmp:1}"
- fi
+ pre_synced=false
+ _sl-get-host-type
+
if [[ $sl_test_hook ]]; then
mq RSYNC_RSH="ssh ${args[*]}" $sl_test_hook "$extra_info" "$remote"
fi
- if $haveinfo && [[ $host_type == sync ]]; then
- info_sec=${tmp::10}
- read -r files_sec _ < <(find -L $SL_FILES_DIR -printf "%T@ %p\n" | sort -nr || [[ $? == 141 || ${PIPESTATUS[0]} == 32 ]] )
- files_sec=${files_sec%%.*}
- # info_sec is the last time we synced to that host. files_sec is the
- # greatest mod time out of files we want to sync.
-
- if (( files_sec > info_sec )); then
- #echo "d4 $files_sec > $info_sec"
- do_rsync=true
- fi
- fi
-
sync_dirname=${SL_FILES_DIR##*/}
-
if [[ ! $SL_FILES_DIR ]]; then
echo 'error: missing SL_FILES_DIR env var' >&2
return 1
fi
- if $do_rsync; then
- # todo: it would be nice if we did this with -v, but
- # only showed the output if the command lasted more than
- # about 4 seconds.
+
+ if [[ $host_type == sync ]] && ! $pre_synced; then
m RSYNC_RSH="ssh ${args[*]}" $sl_rsync_cmd -rptL --delete $SL_FILES_DIR "$remote":
- fi
- if $do_rsync || ! $haveinfo; then
- if [[ $sshinfo && -e $sshinfo ]]; then rm -f $sshinfo; fi
+
sshinfo=$SL_INFO_DIR/$EPOCHSECONDS-$host_type-"$remote"
[[ -e $SL_INFO_DIR ]] || mkdir -p $SL_INFO_DIR
- # debug
- #echo d3: $sshinfo
printf "%s\n" "$extra_info" >$sshinfo
chmod 666 $sshinfo
fi
+
if [[ $host_type == sync ]]; then
if (( ${#@} )); then
# in the past, I used ${@@Q} passed to a bash subshell. Then
# didn't see any benefit to doing it that way (perhaps forgot what
# I originally saw in it).
mq command ssh "${args[@]}" "$remote" \
- LC_USEBASHRC=t . $sync_dirname/.bashrc\; "$@"
+ LC_USEBASHRC=t . $sync_dirname/.bashrc\; "$@"
elif [[ ! -t 0 ]]; then
# This case is when commands are being piped to ssh.
# Normally, no bashrc gets sourced.
fi
# this function inspired from https://github.com/Russell91/sshrc
}
+# sl dev notes:
+#
+# todo: it would be nice if -v would do verbose rsync, but only show the
+# output if it took longer than 4 seconds or so.
+# todo: try running slowdo on verbose ssh
+
slr() {
sl --rsync "$@"