Contact
Christopher Bock <christopher@bocki.com>
cb on irc.oftc.net
crpb on irc.libera.chat
some of my shell functions / aliases
1 alias envi='env -i HOME=$HOME TERM=$TERM PATH=$(getconf PATH)'
2 alias patterns='man 7 apt-patterns |\grep --colour -E "(~|\?)[a-Z]+"'
3 alias debian_pin_helper='apt-cache policy| sed "s/o=/\n\tORIGIN=/g;s/a=/\n\tARCHIVE=/g;s/n=/\n\tCODENAME=/g;s/v=/\n\tVERSION=/g;s/l=/\n\tLABEL=/g;s/c=/\n\tCOMPONENT=/g;s/b=/\n\tARCHITECTURE=/g"'
4 alias debian_release='wget -O- -q http://deb.debian.org/debian/dists/stable/Release |awk "/^(Suite|Codename|Version|Description):/" |paste - - - -'
5 alias debian_releases='wget -O- -q http://deb.debian.org/debian/dists/{oldoldstable,oldstable,stable,testing,unstable,experimental}/Release |awk "/^(Suite|Codename|Description):/" |paste - - - |expand -t 20'
6 alias debian_channels='curl -s https://wiki.debian.org/IRC |grep -Po "(?<=>)#.*?(?=<)" |sort |uniq'
7 alias diff='diff --color --exclude=".git" --exclude="__pycache__"'
8 alias glog='git log --graph --decorate=full --name-status'
9 alias glogf='git log --graph --decorate=full --follow -p'
10 alias gloga='git log --graph --decorate=full --name-status --all ^'
11 alias trente-ente='t=~/.RHABARBERBARBARA; rm -f $t; ssh-keygen -t ed25519 -P "" -f $t >/dev/null; cat $t.pub |xsel -b ; cat $t |xsel -p ; rm -f $t $t.pub'
12 alias secbash='systemd-run --pty --property=DynamicUser=yes /bin/bash --norc'
13 alias seczsh='systemd-run --pty --property=DynamicUser=yes /bin/zsh --no-rcs'
14
15
16 # print apt_log w/o so much clutter
17 apt_hist() {
18 #test -z $(dpkg --print-foreign-architectures) && DELARCH=":$(dpkg --print-architecture)" || DELARCH="RHABARBER" # Only show arch on multiarch system
19 DELARCH=":$(dpkg --print-architecture)"
20 awk '!/^End|^Error:/ { gsub( /\([^()]*\)/ ,"" );
21 gsub(/ ,/,""); gsub(/^(Commandline|Start-Date): /,"");
22 sub(/^Install: /,""); print}' <(zcat -f -- $(find /var/log/apt/history.log* |tac) 2>/dev/null) |sed "s#$DELARCH##g"
23 #print}' <(zcat -f -- $(find /var/log/apt/history.log* |sort -rV) 2>/dev/null) |sed "s#$DELARCH##g" #alternativ
24 }
25
26 # get screenshot url's for package*
27 dscreenshot() {
28 {
29 for package in "$@"; do
30 printf '\thttps://screenshots.debian.net/package/%s\n' "$package"
31 command psql "postgresql://udd-mirror:udd-mirror@udd-mirror.debian.net/udd" -qAt -F $'\t' --command="select package,version,large_image_url from screenshots where package LIKE '"$package"' ORDER BY version ASC"
32 done
33 }
34 }
35 compdef '_deb_packages avail' dscreenshot
36
37 apt_show_source() {
38 {
39 apt show ${1:-*} |& sed '1,3d' |awk '/^(Package|APT-Sources): / {$1=""; print $NFR}' |sed 'N;s/\n/\t/' |expand -t $(( $COLUMNS / 3 ))
40 }
41 }
42 compdef '_deb_packages avail' apt_show_source
43
44 apt_show_maintainer() {
45 apt show "${1:-*}" |& sed '1,3d' |awk '/^(Package|Maintainer): / {$1=""; print $NFR}' |sed 'N;s/\n/\t/' |expand -t $(( $COLUMNS / 3 ))
46 }
47 compdef '_deb_packages avail' apt_show_maintainer
48
49 # show estimated disk-usage of all installed packages
50 dpkg_installedsize() {
51 dpkg-query -Wf '${Installed-Size}\n' | \
52 awk '{ sum += $1 } END { print sum/1024" MB" }'
53 }
54
55 # Get latest netinst.iso
56 debian_download_netinst() {
57 (
58 ARCH="${1:-amd64}"
59 URL="https://cdimage.debian.org/debian-cd/current/$ARCH/iso-cd"
60 DEBTMP=
61 DEBTMP="$(command mktemp --suffix=debiancd -d)"
62 command gpg --keyserver keyring.debian.org --recv-keys 64E6EA7D 6294BE9B 09EA8AC3
63 cd $DEBTMP || return 1
64 command wget -P $DEBTMP $URL/SHA512SUMS{,.sign} || return 1
65 ISO="$(command awk '/debian-[0-9.]*-'$ARCH'-netinst.iso$/ {print $2}' $DEBTMP/SHA512SUMS)"
66 printf "\n\v\tThe current ISO is %s\n\v\tEnter for yes, Ctrl-c for no\v" $ISO
67 read accept
68 command wget -P $DEBTMP $URL/$ISO || return 1
69 command gpg --with-fingerprint --verify $DEBTMP/SHA512SUMS.sign || return 1
70 command shasum --ignore-missing --check $DEBTMP/SHA512SUMS || return 1
71 command printf "Finished download:\n\v\t%s\v\n" $DEBTMP/$ISO
72 )
73 }
74
75 # deb822 formated .sources
76 deb822() {
77 local list # sources
78 if [ -t 0 ]; then
79 list="$(cat ${1:-/usr/share/doc/apt/examples/sources.list})"
80 else
81 list="$(cat /dev/stdin)"
82 fi
83 # sources="$(dirname $list)/$(basename $list |sed 's/\.list/\.sources/')"
84 echo $list | sed -e 's/\[.*\]//g' -e 's/^[\t ]*//g' | \
85 awk '/^deb/ {
86 printf "Types: "$1"\nURIs: "$2"\nSuites: "$3"\nComponents: "; $1=$2=$3="";
87 sub(/^[ \t]+/, ""); printf $0"\nEnabled: yes\n#Signed-By: \n\n"}' # | sudo tee -a $sources
88 # sudo mv $list $list.bak
89 }
90
91 # deb822 print sources
92 deb822_list() {
93 for f in $(echo /etc/apt/sources.list.d/*${1}*.sources); do
94 printf "${f}\n%80s\n" |tr " " "#"
95 cat "${f}"
96 done
97 }
98
99
100 # Size of all Packages Installed
101 dpkg_installedsize() {
102 dpkg-query -Wf '${Installed-Size}\n' | \
103 awk '{ sum += $1 } END { print sum/1024" MB" }'
104 }
105
106 archive_lookup() {
107 command -v jq curl >/dev/null || return 1
108 local URL RET D
109 URL="$1"
110 #RET=( $(curl "http://archive.org/wayback/available?url=$(urldecode "$URL")" |jq -r '.archived_snapshots?|.closest.timestamp,.closest.url'))
111 for timestamp in 19700000000 20991231235959; do
112 RET=( $(curl "http://archive.org/wayback/available?timestamp=${timestamp}&url=${URL}" |jq -r '.archived_snapshots?|.closest.timestamp,.closest.url'))
113 D=${RET[1]}
114 if ! [ $D = null ]; then
115 D="${D::4}-${D:4:2}-${D:6:2}T${D:8:2}:${D:10:2}+${D:12:2}:00"
116 printf 'Date: %s URL: %s\n' "$D" "${RET[2]}"
117 fi
118 done
119 }
120
121 pastebin() {
122 { if [ -t 0 ]; then
123 cat $1
124 else
125 cat /dev/stdin
126 fi } | command -p pastebinit |sed 's%/hidden/%/plainh/%'| tee >(tr -d "\n"| xclip -i -selection clipboard) |tee -a ~/.pastebinit_history
127 # local archive...
128 local URL PASTEID
129 URL="$(xclip -selection clipboard -o |sed 's/\/$//g')"
130 PASTEID=${URL##*/}
131 wget --quiet "$(xclip -selection clipboard -o |sed 's/\/$//g')" --output-document="$HOME/.pastebinit_history.d/$PASTEID"
132 }
133
134 # PASTE LATEST SCREENSHOT
135 0x0() {
136 local file img url ttl=96 histfile=~/.0x0_history res dir=~/snips
137 if [ "$1" = "-h" ]; then
138 cat << EOF
139 Usage: arg[1] = filename or nothing for newest file in $dir
140 -h for help
141 -f for fuzzy thingy
142 -d for printing curl statements for all tokens
143 EOF
144 elif [ "$1" = "-f" ]; then
145 awk 'NF>2' $histfile |
146 fzf --disabled \
147 --bind="p:execute:sensible-browser {2}" \
148 --bind 'd:preview:command curl -s -Fdelete= -Ftoken="{3}" {2}' \
149 --preview-window=up \
150 --header "p: sensible-browser URL; d: delete on 0x0; return: print curl to cli in background" \
151 --bind 'enter:execute:echo curl -Fdelete= -Ftoken="{3}" {2}'
152 elif [ "$1" = "-d" ]; then
153 awk '{printf "curl -Ftoken=%s -Fdelete= %s\n", $3, $2}' $histfile
154 else
155 file="$(print "$dir"/*(.om[1]))"
156 img="${1-$file}"
157 # '${${img}:a:q}' only works with zsh. you will need an alternative in bash
158 printf '%s\nfile://%s\nPress Enter to upload! ' ${${img}:a:q} ${${img}:a:q}
159 # printf 'file://%s\n' ${${img}:a:q}
160 read accept
161 # curl -s -F"file=@${img}" -Fexpires=96 -Fsecret= https://0x0.st | \
162 # tee >(tr -d '\n'| xsel -i -b)
163 res=( $(curl --write-out '%header{x-token}' -s -F"file=@${img}" -Fexpires=$ttl -Fsecret= https://0x0.st) )
164 printf '%s' "${res[1]}" | xsel -i -b
165 printf '%s\t%s\t%s\t%s\n' "$(date -Im)" "${res[1]}" "${res[2]}" "${file}" |tee -a "${histfile}"
166 fi
167 }
168
169 # Fluxbox apps helper
170 fbxprop() {
171 printf '[app] %s \n[end]\n' "$(
172 xprop WM_CLASS WM_NAME WM_WINDOW_ROLE |
173 sed 's/WM_\(.*\)(\(.*\)) = "//g;s/", "/\n/;s/"$//'|
174 sed '1 s/^/(name=/;2 s/^/(class=/;3 s/^/(title=/;4 s/^/(role=/;s/$/)/g' |
175 # WM_WINDOW_ROLE might not be found
176 grep -v WM_WINDOW_ROLE |tr '\n' ' ')"
177 }
178
179
180 tmux_cssh() {
181 local split match name hosts OPTS
182 if test $# -ge 3 ; then
183 if [[ $3 =~ ^[0-9]+$ ]]; then
184 split="$3"
185 fi
186 fi
187 if test $# -ge 2 ; then
188 match="$1"
189 if [[ $2 =~ ^[0-9]+$ ]] && [[ $# = 2 ]]; then
190 split="$2"
191 name="$(tr -cd '[:alnum:]' <<< "$1")"
192 else
193 name="$2"
194 fi
195 fi
196 if test $# = 1 ; then
197 if test -z "$(tr -d '[:alnum:]' <<< "$1")"; then
198 match="$1."
199 name="$1"
200 else
201 match="$1"
202 name="$(tr -cd '[:alnum:]' <<< "$1")"
203 fi
204 fi
205 if test $# = 0 ; then
206 return 0
207 fi
208 OPTS=(-ts "${name}" -sa -A)
209 if ! test -z $split ; then OPTS=(${OPTS[@]} -sw "$split"); fi
210 echo tmux-cssh ${OPTS[@]} $(awk '/^Host .*('$match').*$/ {printf "%s ", $2}' ~/git/ssh_config/*.ssh ~/.ssh/config)
211 tmux-cssh "${OPTS[@]}" $(awk '/^Host .*('$match').*$/ {printf "%s ", $2}' ~/git/ssh_config/*.ssh ~/.ssh/config)
212 }
213
214 _cows() {
215 ( command -v cowsay lolcat faketime || sudo apt install --yes cowsay lolcat faketime ) >/dev/null 2>&1
216 OPTS=( -b -d -g -n -p -s -t -w -y ); for opt in ${OPTS[@]}; do echo "${1:=MUUUH}" |cowsay $opt |lolcat ; done
217 for tach in 12-25 08-16 11-07 02-18 04-01; do faketime 2022-$tach apt-get moo| lolcat; done
218 apt-get -o APT::Moo::Color=true moo moo
219 }
220
221 # QEMU RUN ISO
222 qemu_iso() {
223 iso="$1"
224 shift
225 qemu-system-x86_64 --enable-kvm --smp 4 -boot d -m 2G \
226 -nic user,ipv6=off,model=vmxnet3 --display gtk --serial stdio \
227 -cdrom "$iso" $@
228 }
229 qemu_serial() {
230 iso="$1"
231 shift
232 qemu-system-x86_64 --enable-kvm --smp 4 -boot d -m 2G \
233 -nic user,ipv6=off,model=vmxnet3 --display curses --nographic --vga none \
234 -cdrom "$iso" $@
235 }
236
237 gdiff() {
238 local N
239 test "$1" -eq "$1" && N="$1" || N=1
240 git diff HEAD~${N} HEAD
241 }
242 gdiffs() {
243 git diff --staged
244 }
245
246 # clone git repo to e.g. ~/git/$sitename/$usercorpname/$reponame
247 gclone() {
248 {
249 if ((DEBUGTHIS)); then set -x; fi
250 testuri() { git ls-remote --quiet $1 HEAD >/dev/null 2>&1 ; }
251 local base url prot link domain subpath usr notld repo rpath
252 base=~/git/
253 url="$1"
254 if ! testuri "$url"; then
255 echo "Couldn't find a git repository at ${url}!" >/dev/stderr
256 return 65
257 fi
258 if [[ "$url" =~ "https?://" ]]; then
259 prot="${url%:*}"
260 link="${url#${prot}://}"
261 domain="${link%%/*}"
262 subpath="${link#${domain}}"
263 elif [[ "$url" =~ "^git@" ]]; then
264 prot="${url%@*}"
265 link="${url#${prot}@}"
266 domain="${link%%:*}"
267 subpath="${link#${domain}:}"
268 fi
269 usr="${subpath%/*}"
270 notld="${domain%.*}"; notld="${notld#git.}"
271 repo="${link##*/}"; repo="${repo%*.git}"
272 rpath="$(realpath -sm "$base/$notld/$usr/$repo"|tr '[:upper:]' '[:lower:]')"
273 if [ -n "$ZSH_VERSION" ] && type zstyle >/dev/null 2>&1; then
274 vared -p "Clone $url to: " rpath
275 elif [ -n "$BASH_VERSION" ] && type caller >/dev/null 2>&1; then
276 rpath="$(read -e -r -p "Clone "$url" to: " -i "$rpath"; echo "$REPLY")"
277 fi
278 if ! test -d "$rpath"; then
279 mkdir -p "${rpath%/*}"
280 git clone "$url" "$rpath"
281 cd $_
282 else
283 printf 'Directory %s already exists!\n' "$rpath"
284 cd $_
285 fi
286 set +x
287 }
288 }
289
290
291
292
293
294 # libvirt shrink all qcow images
295 libvirt_shrink_qcow() {
296 VMSR=( $(virsh --quiet --connect=qemu:///session list --state-running --name) )
297 VMS=( $(virsh --quiet --connect=qemu:///session list --all --name) )
298 for VM in "${VMSR[@]}"; do
299 printf "Stopping VM: $VM\n"
300 virsh --quiet --connect=qemu:///session shutdown --domain $VM
301 sleep 0.5
302 done
303 while true; do
304 if [[ -z $(virsh --quiet --connect=qemu:///session list --state-running --name) ]]; then
305 break
306 else
307 printf "VMs still running: %s\n" "$(virsh --quiet --connect=qemu:///session list --state-running --name |tr '\n' ' ')"
308 printf "Waiting 5 seconds to check again\n"
309 sleep 5
310 fi
311 done
312 printf "\n"
313 for VM in "${VMS[@]}"; do
314 printf "VM: $VM\n"
315 for IMG in $(virsh --quiet --connect=qemu:///session domblklist --details --domain $VM | awk '/disk.*qcow2$/{print $NF}'); do
316 printf "Compressing $IMG\n"
317 time qemu-img convert -p -c -O qcow2 $IMG $IMG.tmp
318 mv -v $IMG{,.bak}
319 mv -v $IMG{.tmp,}
320 ls -1sh ${IMG}*
321 printf "\n"
322 BAKS="${BAKS} ${IMG}.bak"
323 done
324 done
325 for VM in $VMSR; do
326 printf "Starting VM: $VM\n"
327 virsh --quiet --connect=qemu:///session start --domain $VM;
328 done
329 printf "\nDon't forget to cleanup the backups:\n rm %s \n" $BAKS
330 }
331
332
333 # libvirt snapshot overview
334 virsnaps() {
335 local DOMS DOM SNAPS TREE CURRENT
336 local SES=${1:-session}
337 DOMS=( $(virsh --quiet --connect=qemu:///${SES} list --all --name) )
338 echo -e "\033[1mDomains: ${DOMS[@]}\033[0m"
339 for DOM in ${DOMS[@]}; do
340 CURRENT="$(virsh --quiet --connect=qemu:///${SES} snapshot-current --name --domain "$DOM" 2>/dev/null)"
341 SNAPS="$(virsh --connect=qemu:///${SES} snapshot-list --topological --parent --domain "$DOM")"
342 TREE="$(virsh --connect=qemu:///${SES} snapshot-list --topological --tree --domain "$DOM")"
343 if [ "${#CURRENT}" -gt 0 ] ; then
344 printf '\033[1mDomain: %s\033[0m\n' "$DOM"
345 printf '%s\n' "$SNAPS"|sed ''/$CURRENT/s//$(printf "\033[1m$CURRENT\033[0m")/''
346 printf 'Tree:\033[0m\n%s\n' "$TREE"|sed ''/$CURRENT/s//$(printf "\033[1m$CURRENT\033[0m")/''
347 fi
348 done
349 }
This script illustrates how you can modify the Cloud images with the help of guestfs-tools for e.g. virt-manager to not bother with manualy resizing the disk + partition and setting up your default environment.
cloud.debian.org-guestfs-tools-shenanigans.sh
1 #!/usr/bin/env sh
2 set -e
3 URL=https://cloud.debian.org/images/cloud
4 DIST="${1:-trixie}"
5 SIZE="${2:-20G}"
6 IMAGE="${3:-nocloud}"
7 PACKAGES="auto-apt-proxy,zsh,vim-nox,vim-airline,vim-ale,systemd-resolved,netplan.io-,grml-etc-core"
8
9 TMPDIR=$(mktemp -t cloudimage.XXXXXX -d)
10 cd "$TMPDIR" || exit 1
11
12 cleanup() {
13 [ $? -eq 0 ] && exit
14 set -x
15 echo "Interrupted, cleaning up!"
16 rm -Rfv "$TMPDIR"
17 set +x
18 exit 1
19 }
20
21 trap cleanup INT HUP
22
23 for pkg in wget guestfs-tools qemu-utils qemu-system; do
24 dpkg-query -W $pkg >/dev/null 2>/dev/null || missing="$pkg $missing"
25 done
26 test -n "$missing" && { echo "Missing packages $missing, exiting."; exit 1 ; }
27
28 # Downloading latest nocloud image
29 # % ARCH=$(dpkg --print-architecture)
30 # % wget -qO- https://cloud.debian.org/images/cloud/trixie/daily/latest/SHA512SUMS | awk -v arch=$ARCH '$2 ~ "debian-[0-9]+-nocloud-"arch".*qcow2"'
31 # ade27b1d7d371e823931af4862cf5aee17f766c68197329c7918f7e275b6d5425fedb1bb5256188da0c98326fea717e674e0d4b463060f01f14544d1d7525208 debian-13-nocloud-amd64-daily.qcow2
32 #
33 ARCH=$(dpkg --print-architecture)
34 printf 'Downloading: %s\n' "$URL"/"$DIST"/daily/latest/SHA512SUMS
35 wget -qP "$TMPDIR" "$URL"/"$DIST"/daily/latest/SHA512SUMS
36 IMG=$(awk -v arch="$ARCH" -v image="$IMAGE" '$2 ~ "debian-[0-9]+-"image"-"arch".*qcow2" {print$2}' "$TMPDIR"/SHA512SUMS)
37 test -n "$IMG" || exit 1
38 printf 'Downloading: %s\n' "$URL"/"$DIST"/daily/latest/"$IMG"
39 wget -qP "$TMPDIR" "$URL"/"$DIST"/daily/latest/"$IMG"
40 printf 'Check SHASUM\n'
41 shasum --ignore-missing --check "$TMPDIR"/SHA512SUMS || exit 1
42
43 # Getting partition name for the ext4 filesystem
44 # % virt-filesystems --filesystems --long -a /tmp/puppet.qcow2
45 # Name Type VFS Label Size Parent
46 # /dev/sda1 filesystem ext4 - 2961358848 -
47 # /dev/sda15 filesystem vfat - 129718272 -
48 #
49 PARTNAME=$(virt-filesystems --filesystems --long -a "$TMPDIR"/"$IMG" |awk '$3=="ext4" {print $1}')
50
51 # Create target img
52 printf '\nCreating qcow2 image: %s\n' "$TMPDIR"/"$SIZE"-"$IMG"
53 qemu-img create -f qcow2 -o preallocation=metadata "$TMPDIR"/"$SIZE"-"$IMG" "$SIZE"
54
55 # Resize daily.qcow2 to new disk
56 printf '\nResizing partition\n'
57 virt-resize --expand "$PARTNAME" "$TMPDIR"/"$IMG" "$TMPDIR"/"$SIZE"-"$IMG"
58
59 # List images and filesystems
60 printf '\nQEMU-IMG INFO: %s\n' "$TMPDIR"/"$SIZE"-"$IMG"
61 qemu-img info "$TMPDIR"/"$SIZE"-"$IMG"
62
63 printf '\nVIRT-FILESYSTEMS: %s\n' "$TMPDIR"/"$SIZE"-"$IMG"
64 virt-filesystems -h -l --all -a "$TMPDIR"/"$SIZE"-"$IMG"
65
66 printf '\n'
67 ls -sSh1 "$TMPDIR"/*
68 printf '\n'
69
70 printf '\nExtracting Kernel\n'
71 virt-get-kernel -o "$TMPDIR" -a "$TMPDIR"/"$SIZE"-"$IMG"
72
73 printf '\nModifying to image to our needs\n'
74 if test -n "$PACKAGES"; then
75 # Add firstboot install task
76 virt-customize --network \
77 --firstboot-install "$PACKAGES" \
78 -a "$TMPDIR"/"$SIZE"-"$IMG"
79 fi
80
81 # Get rid of netplan and do some things like enabling the GRML repository and
82 # switching the default shell to zsh.
83 # NOTE: This will run before --firstboot-install
84 SCRIPT="$TMPDIR"/firstbootscript
85 cat <<EOF > "$SCRIPT"
86 # silly https links..
87 sed -i 's/https/http/g' /etc/apt/mirrors/*.list
88 # networkd dhcp fallback
89 printf '[Match]\nType=ether\n\n[Network]\nDHCP=yes\n\n[DHCPv4]\nUseDomains=true\nClientIdentifier=mac\n' > /etc/systemd/network/80-dhcp.network
90 apt-get --yes --update --purge --auto-remove install grml-keyring systemd-resolved
91 ln -vs /usr/share/grml-keyring/grml.sources /etc/apt/sources.list.d/
92 systemctl --now enable systemd-networkd systemd-resolved
93 apt-mark -o Debug::AptMark::Minimize=true minimize-manual --yes
94 chsh -s/bin/zsh
95 sed -i '/^#DSHELL/aDSHELL=/bin/zsh' /etc/adduser.conf
96 EOF
97
98 virt-customize --network \
99 --firstboot "$SCRIPT" \
100 -a "$TMPDIR"/"$SIZE"-"$IMG"
101
102
103 # TEST IT? (you likely need to change the -net options)
104 # It is defined in dash(1): read [-p prompt] [-r] variable [...]
105 # shellcheck disable=SC3045
106 read -p "Run QEMU-TEST? [y/N]: " -r qemu
107 case $qemu in
108 [Yy]* )
109 qemu-system-$(uname --machine) --enable-kvm --smp 2 -m 2G -net bridge,br=br0 \
110 -net nic,model=virtio --display gtk --serial stdio \
111 -drive file="$TMPDIR"/"$SIZE"-"$IMG"
112 true ;;
113 [Nn]* ) true ;;
114 esac
