add some content

This commit is contained in:
Jörn-Michael Miehe 2025-10-29 17:55:38 +01:00
parent 30cd30bbdf
commit ac1803fc00
6 changed files with 371 additions and 5 deletions

5
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"recommendations": [
"timonwong.shellcheck"
]
}

25
LICENSE
View file

@ -1,9 +1,24 @@
MIT License
This is free and unencumbered software released into the public domain.
Copyright (c) 2025 jmm
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

252
bin/citrix-update Executable file
View file

@ -0,0 +1,252 @@
#!/bin/bash
# name: citrix-update
# summary: Startup script: Downloads and installs "Citrix Workspace"
# params: none
########
# INIT #
########
# find all download links on update page
# find corresponding checksums
has_command() { # $command
command -v "$1" &>/dev/null
}
needs_commands() { # $cmd1 $cmd2 ...
local cmd
for cmd in "${@}"; do
if ! has_command "${cmd}"; then
echo "Command '${cmd}' not available!" >&2
return 1
fi
done
return 0
}
needs_commands "xidel"
echo -n "Downloading citrix update page ... " >&2
html_data="$(curl -sSfL 'https://www.citrix.com/downloads/workspace-app/linux/workspace-app-for-linux-latest.html')"
echo "OK!" >&2
# # XPath playground
# echo "${html_data}" | xidel - \
# --silent \
# --printed-node-format text \
# --extract "links:=//div[contains(@class, 'ctx-dl-content')]//a[contains(@class, 'ctx-dl-link') and @rel]/@rel" \
# --extract "csums:=//div[contains(@class, 'ctx-dl-content')]//ul[contains(@class, 'ctx-checksum-list')]/li[1]/text()"
# exit 0
# parse using XPath
declare -a links csums
eval "$( \
echo "${html_data}" | xidel - \
--silent \
--output-format bash \
--extract "links:=//div[contains(@class, 'ctx-dl-content')]//a[contains(@class, 'ctx-dl-link') and @rel]/@rel" \
--extract "csums:=//div[contains(@class, 'ctx-dl-content')]//ul[contains(@class, 'ctx-checksum-list')]/li[1]/text()" \
)"
# ensure every link has a checksum
if [[ "${!links[*]}" != "${!csums[*]}" ]]; then
echo "Links and Checksums don't match up!" >&2
exit 1
fi
# postprocess data
declare -A citrix_data
for key in "${!links[@]}"; do
link="${links["${key}"]}"
# if link starts with "//" (no protocol), assume https
if [[ "${link}" == "//"* ]]; then
link="https:${link}"
fi
# extract checksum only (64 hex digits)
csum="$( echo "${csums["${key}"]}" | grep -Eo "\<[[:xdigit:]]{64}\>" )"
citrix_data["${csum}"]="${link}"
done
# remove intermediate containers
unset links csums
#########
# FUNCS #
#########
find_link() { # $filename_regex
local link_regex="://downloads\.citrix\.com/[[:digit:]]+/${1}\?__gda__=exp=[[:digit:]]+~acl=[^~]+~hmac=[[:digit:]a-f]{64}$"
for key in "${!citrix_data[@]}"; do
if echo "${citrix_data["${key}"]}" | grep -E "${link_regex}" &>/dev/null; then
echo "${key} ${citrix_data["${key}"]}"
fi
done
}
find_link_deb() { # $name $arch
case "${2}" in
x86_64) local arch="amd64" ;;
arm64) local arch="arm64" ;;
*) local arch="${2}" ;;
esac
find_link "${1}_[[:digit:]\.]+_${arch}\.deb"
}
find_link_rpm() { # $name $flavor $arch
find_link "${1}(:?-${2})?-[[:digit:]\.]+(:?-[[:digit:]]+)?.${3}\.rpm"
}
find_link_targz() { # $arch
case "${1}" in
x86_64) local arch="x64" ;;
arm64) local arch="arm64" ;;
*) local arch="${1}" ;;
esac
find_link "linux${arch}-[[:digit:]\.]+\.tar.gz"
}
# shellcheck disable=SC2155
list_all() {
local debs="$(find_link_deb "[[:lower:]]+" "[[:alnum:]]+")"
local debc="$(echo "${debs}" | wc -l)"
echo "deb:"
echo "${debs}"
local rpms="$(find_link_rpm "[[:alpha:]]+" "[[:lower:]]+" "[[:alnum:]_]+")"
local rpmc="$(echo "${rpms}" | wc -l)"
echo "rpm:"
echo "${rpms}"
local tars="$(find_link_targz "[[:alnum:]]+")"
local tarc="$(echo "${tars}" | wc -l)"
echo "tar.gz:"
echo "${tars}"
local anys="$(find_link "[[:alnum:]\._-]+")"
local anyc="$(echo "${anys}" | wc -l)"
echo "any:"
echo "${anys}"
if [ $(( debc + rpmc + tarc )) -ne $(( anyc )) ]; then
echo "Not all links matched!" >&2
exit 1
fi
}
download_gui() { # $link $csum $destfile
needs_commands "curl" "zenity" "sha256sum" || return 1
echo "Downloading '${1}' to '${3}'"
curl -fL -o "${3}" "${1}" &
local curlpid=$!
yes | zenity \
--progress --pulsate --auto-close \
--title="Downloading" \
--text="Downloading '${3}' ..." &
local zenpid=$!
while kill -0 "${curlpid}" 2>/dev/null; do
if ! kill -0 "${zenpid}" 2>/dev/null; then
# progress bar died; ask for abort
if zenity \
--question \
--text="Abort Download?"; then
kill "${curlpid}" 2>/dev/null || true
echo "Download cancelled!" >&2
break
fi
# restart progress bar
yes | zenity \
--progress --pulsate --auto-close \
--title="Downloading" \
--text="Downloading '${3}' ..." &
zenpid=$!
fi
sleep 0.2
done
kill "${zenpid}" 2>/dev/null || true
wait "${curlpid}"
if [ "$( sha256sum "${3}" | cut -d' ' -f1 )" = "${2}" ]; then
echo "SHA256 ${2} OK!" >&2
return 0
else
echo "SHA256 ${2} mismatch!" >&2
return 1
fi
}
install_deb() { # $name
needs_commands "dpkg-query" "gdebi-gtk" || return 1
local arch
arch="$(uname -m)"
echo "Trying to install ${1} DEB for ${arch}" >&2
local link
if ! link="$(find_link_deb "${1}" "${arch}")"; then
echo "No DEB found!" >&2
return 1
elif [ "$(echo "${link}" | wc -l)" -ne 1 ]; then
echo "More than one DEB found!" >&2
return 1
fi
local csum
csum="$( echo "${link}" | cut -d' ' -f1 )"
link="$( echo "${link}" | cut -d' ' -f2 )"
local version_available
version_available="$(echo "${link}" | sed -r 's/^.*\/[^_]+_([[:digit:]\.]+)_[^\.]+\.deb.*$/\1/')"
local version_installed
if version_installed="$(dpkg-query --show --showformat='${Version}\n' ${1} &> /dev/null)" \
&& [ "${version_available}" = "${version_installed}" ]; then
echo "Newest version already installed!" >&2
return 0
fi
if ! zenity \
--question \
--title="New Version Available" \
--text="<span size=\"xx-large\">Citrix Upgrade Available!</span>\n\nInstall ${1} version <b>${version_available}</b> now?"; then
echo "Installation of ${1} cancelled!" >&2
return 0
fi
local destfile
destfile="$(mktemp --tmpdir "XXXXX_${1}_${version_available}.deb")"
if download_gui "${link}" "${csum}" "${destfile}"; then
echo "Download for ${1} successful!" >&2
gdebi-gtk "${destfile}"
fi
rm -f "${destfile}"
echo "Cleaned up '${destfile}'" >&2
return 0
}
########
# MAIN #
########
list_all > /dev/null
if has_command "apt"; then
install_deb "icaclient" || exit 1
install_deb "ctxusb" || exit 1
fi
exit 0

66
bin/system-update Executable file
View file

@ -0,0 +1,66 @@
#!/bin/sh
# name: system-update
# summary: - runs all relevant update commands for a machine
# - automatically detects and handles apt, snap and flatpak
# - fully POSIX shell compliant
# params: none
# check if a command is available
has_command() { # $command
command -v "$1" 1>/dev/null 2>/dev/null
}
# run self as root
if [ "$(id -u)" -ne 0 ]; then
if has_command sudo; then
# shellcheck disable=SC2068
exec sudo "$(readlink -f "$0")" $@
else
echo "This script is designed to be run as root!"
exit 1
fi
fi
# handle apt packages
if has_command apt-get; then
set -ex
# update package sources
apt-get --yes update
# upgrade installed packages
apt-get --yes dist-upgrade
# remove unused dependencies
apt-get --yes --purge autoremove
# remove leftover local archives
apt-get --yes autoclean
# remove leftover config files
apt-get --yes purge '?config-files'
set +ex
fi
# handle snaps
if has_command snap; then
set -ex
# upgrade installed snaps
snap refresh
# remove disabled snaps: https://askubuntu.com/a/1040131
set +x
env LANG=en_US.UTF-8 snap list --all \
| awk '/disabled/{print $1, $3}' \
| while read -r snap_name snap_revision; do
set -x
snap remove "${snap_name}" --revision="${snap_revision}"
set +x
done
set +ex
fi
# handle flatpaks
if has_command flatpak; then
set -ex
# upgrade installed flatpaks
flatpak update --noninteractive
# remove unused flatpaks
flatpak uninstall --noninteractive --unused
set +ex
fi

25
conf/profile Normal file
View file

@ -0,0 +1,25 @@
#!/bin/sh
_include_bindir_in_path() {
if [ -d "${1}" ]; then
real_bin_dir="$(readlink -f "${1}" )"
export PATH="${real_bin_dir}:${PATH}"
fi
}
# include ~/bin and ~/bin.d/* in PATH
for bin_candidate in "${HOME}/bin/" "${HOME}/bin.d/"*; do
_include_bindir_in_path "${bin_candidate}"
done
# ... also include a few well-known bin directories
for bin_location in ".local" ".poetry" ".cargo"; do
_include_bindir_in_path "${HOME}/${bin_location}/bin/"
done
# ... include ALL OF THE ~/.whatever/bin directories (possibly unsafe)
# for bin_candidate in "${HOME}/."*"/bin/"; do
# _include_bindir_in_path "${bin_candidate}"
# done
unset -f _include_bindir_in_path

3
conf/zshenv Normal file
View file

@ -0,0 +1,3 @@
#!/bin/zsh
alias apt-install-url='function _apt-install-url(){ local destfile="$(mktemp --suffix ".deb")"; wget --quiet --show-progress --output-document "${destfile}" "${1}"; sudo apt install "${destfile}"; rm -f "${destfile}"; unset -f _apt-install-url; }; _apt-install-url'