├── .gitignore ├── .hostrun ├── .mailmap ├── @ ├── LICENSE ├── Makefile ├── README.md ├── annex-abslink ├── archlog ├── arpaname ├── asn1 ├── asplog ├── bin ├── .signature ├── addr2names ├── annex ├── annex-addplaceholder ├── annex-du ├── annex-dup ├── annex-dupes ├── annex-dwim-remote ├── annex-format-log ├── annex-list-format ├── annex-placeholder ├── annex-purge ├── annex-remotes ├── annex-store ├── annex-where ├── askpin ├── ata-secure-erase ├── axfr ├── backup ├── borgdf ├── bus ├── cachedir-tag ├── cap-upload.sh ├── capsled ├── capture ├── catznip ├── cdrip ├── chfont ├── cpuctl ├── cron.dropbatch ├── cronjob ├── ctl ├── dataurl ├── dbus-name ├── dd ├── describe-mac ├── diskuse ├── dmenu-print-history ├── dmenu_run ├── dnssec-dsfromdns ├── domainsort ├── dupes ├── emergency-su ├── expandzones ├── ffconcat ├── ffdownscale ├── ffmpeg ├── ffplay ├── ffprobe ├── find-computer-name ├── find-glyph ├── find-setuid ├── findbroken ├── findglue ├── findicase ├── firestorm ├── fix-mpv-names ├── fontview ├── funsync ├── genll ├── genmac ├── git-alternate ├── git-checksrc ├── git-local-tags ├── git-lspacks ├── git-mirror ├── git-rconfig ├── git-show-merge ├── git-show-replaced ├── git-tag-v-all ├── git-url ├── git-url-handler ├── git-verify-mailmap ├── gmount ├── gnome-inhibit ├── gpg-get-missing ├── gpg-protect-tool ├── gpg-test-import ├── gpg-unprotect ├── gumount ├── gw-core-console ├── hide ├── hlsrip ├── hpavctl ├── imgrgb ├── imv ├── interval ├── ip-autoconf ├── ip-mask ├── ip-subnet ├── ip-summarize ├── java-redir ├── json2json ├── json2toml ├── json2yaml ├── kc ├── kc.sh ├── kl ├── kokua ├── kzgrep ├── ldap ├── ldifunwrap ├── ldmissing ├── libfilterfile.bash ├── libhttpfetch.bash ├── libks.bash ├── logout ├── lsar ├── lsdri ├── lsimap ├── lsusb.py ├── mac2ll ├── mikrotik-copy-id ├── mksshfp ├── mkwindowsurl ├── mosh-detach ├── mtime ├── nightlight ├── nm-list-wifi ├── nm-wifi-list ├── nolid ├── nosymlinks ├── outdent ├── paccat ├── pacrename ├── pcf2otb.pe ├── pfb2otf.pe ├── pftp ├── ping6 ├── prename ├── progress ├── putenv ├── pydrac ├── rdempty ├── readcoff ├── recent ├── rechmod ├── rel ├── reserialize ├── restrainedlove ├── rgba ├── rotate-up ├── run-secondlife ├── saucenao ├── schema2ldif ├── secondlife ├── sendtestmail ├── sfnet-backup ├── signa ├── smbping ├── ssh-duphosts ├── ssh-pkcs11 ├── ssh2pem ├── sshmux ├── store-secret ├── swaks-gmail ├── swaks-null ├── swaks-uk ├── tarball ├── telnet-uri-helper ├── termprogress ├── testcidr ├── testrad ├── toml2json ├── toml2toml ├── toml2yaml ├── trackerwatch ├── trash ├── tweak ├── unar ├── unhexdump ├── unison ├── unrename ├── unwipefs ├── unzlib ├── update-winbox ├── upmove ├── upower-monitor ├── uri ├── urimap ├── urlencode.pl ├── urlparse ├── verbose ├── vers ├── wg-debug ├── whatowns ├── windows ├── wpa_debuglevel ├── wrappers │ ├── catznip │ ├── cower │ ├── dd │ ├── ffmpeg │ ├── firestorm │ ├── gens │ ├── gio │ ├── kokua │ ├── pacman │ ├── restrainedlove │ ├── secondlife │ ├── signa │ └── unison ├── xdg-open ├── xfrm2shark ├── xhead ├── xsauce ├── xterm-color-chooser ├── yaml2json ├── yaml2toml ├── yaml2yaml ├── ytdl ├── ytdl-m4a ├── ytdl-mkv ├── ytdl-mp3 ├── ytdl-mp4 ├── ytdl-mp4-1080p ├── ytdl-mp4-480p ├── ytdl-mp4-720p └── zipball ├── cap ├── charge ├── cisco ├── ciscoplug ├── countdown ├── cputemp ├── darkmode ├── dhcpclassless ├── dhcpsearch ├── dist ├── bootstrap ├── configure ├── empty.c ├── guess.mk ├── prepare ├── pull ├── shared.mk └── update-thirdparty ├── dropbatch ├── each ├── egrep ├── envcp ├── fallback ├── cower ├── diff-highlight ├── finger ├── hex ├── hostname ├── nproc ├── strftime ├── telinit ├── unhex ├── urlencode └── zlib ├── fattr ├── fattr.old ├── fgrep ├── fqdn ├── gclip ├── getnetrc ├── gettermbg ├── git-new ├── git-up ├── gsstoken ├── hi ├── htelnet ├── iata ├── icao ├── ifpeer ├── irc ├── isterm ├── kerberos ├── Makefile ├── k5translate ├── k5userok.1 ├── k5userok.c ├── kc ├── kc.bash ├── kc.md ├── kc.sh ├── kl ├── krb5-find-legacy-keys.py ├── krb5.h ├── kroute ├── lskeytab ├── pkinit ├── pklist.1 ├── pklist.c └── pklist.md ├── kf ├── lastdown ├── lastwake ├── lcpkg ├── lda ├── less ├── lib.bash ├── lib ├── cidr.cs ├── cidr.php ├── cidr.ps1 ├── kc.bash ├── perl5 │ └── Nullroute │ │ ├── Dir.pm │ │ ├── LDAP.pm │ │ ├── Lib.pm │ │ ├── Str.pm │ │ ├── Term.pm │ │ └── _Lib.pl ├── php │ ├── sexp-parser.php │ ├── syslog.php │ └── time-age.php ├── python │ ├── authorized_keys.py │ └── nullroute │ │ ├── core.py │ │ ├── file.py │ │ ├── io.py │ │ ├── irc │ │ ├── __init__.py │ │ └── parse.py │ │ ├── misc.py │ │ ├── mp3tags.py │ │ ├── net.py │ │ ├── oath.py │ │ ├── oauthutil.py │ │ ├── renameutil.py │ │ ├── scrape.py │ │ ├── sec │ │ ├── __init__.py │ │ ├── dpapi.py │ │ ├── oauth2.py │ │ ├── pine.py │ │ └── sasl.py │ │ ├── sexp.py │ │ ├── string │ │ ├── __init__.py │ │ └── imaputf7.py │ │ ├── system │ │ ├── statx.py │ │ └── utmp.py │ │ ├── test-keys.txt │ │ ├── ui │ │ ├── __init__.py │ │ ├── progressbar.py │ │ ├── wcwidth.py │ │ └── win32.py │ │ ├── urlcache.py │ │ └── windows │ │ ├── __init__.py │ │ └── registry.py ├── test_on ├── testlib.bash ├── testlib.pl └── testlib.py ├── llpkg ├── loc ├── lshung ├── lsort ├── lspkg ├── lspkgs ├── man ├── misc ├── DH ├── Deprovision-Appx.ps1 ├── Makefile ├── Send-Syslog.ps1 ├── Send-WakeOnLan.ps1 ├── VBoxHeadlessVRDE ├── ac-wait.c ├── adoc-extract-certs ├── airmon ├── arch │ ├── arch-downgrade │ ├── checkmirrors │ ├── fakepkg │ ├── mkloaderconf │ ├── mkloaderconf.path │ ├── mkloaderconf.service │ ├── pacverify │ ├── pacwhy │ └── sign-kernels ├── args.c ├── arpawalk ├── askpin.py ├── audit-decode-proctitle ├── babyl.txt ├── babyl2mbox ├── backtick ├── backup.py ├── bencode-print ├── bird-bgpath ├── bird2names ├── bluez_nap_client.py ├── bogomark ├── burn-iso ├── check-ldap-sync ├── cputempwatch ├── cron.dropbatch ├── dbx-keystore ├── ddrescue2dust.py ├── dejetty ├── denettalk ├── desecondlife ├── diskuse.new ├── dmenu_run ├── do_rsync ├── dropbatch.path ├── dropbatch.service ├── dropbatch.timer ├── dxvk ├── ecryptfs-mount-x11 ├── emergency-su.c ├── enumname ├── eth0-dhcp ├── fatattr.c ├── feature.h ├── fidoname ├── finger.py ├── finger.sh ├── firebird-dump-table ├── fit ├── fujitsu-backlight ├── fujitsu-rotate-screen ├── fujitsu-tablet-mode ├── gai ├── gai.pl ├── gencommit ├── getai ├── gettime.c ├── git-all-gc ├── git-all-repack ├── git-branch-info ├── git-credential-netrc ├── git-credential-readonly ├── git-extract-tag ├── git-find-blob ├── git-link-history ├── gl-mem.c ├── gmail-oauth ├── gnome-mpris-inhibit ├── gnome-mpris-keybind ├── gpg-sync-keyrings ├── gpgin ├── gpgout ├── hex.c ├── hg-up ├── http-mosaic-proxy ├── hugin-stitch ├── i3lock.fujitsu ├── id3-cover ├── id3-fix-rg ├── id3-lyrics ├── id3-purge-priv ├── id3-sync-rg ├── imgur ├── import-arch-keyring ├── ipseckey ├── irc-bot.py ├── irc-proxymux ├── irssi │ ├── auth_quakenet.pl │ ├── auth_webirc.pl │ ├── cap_authen_sasl.pl │ ├── coffee.pl │ ├── scrollwarn.pl │ ├── server-time.pl │ └── sleep_disconnect.pl ├── is-attached ├── issunpack.py ├── kzak_ttyutils.h ├── ldif2passwd.py ├── libfunsync.c ├── lsdefines ├── lsdomain ├── lsh-import-key ├── lsram ├── maildir-layout ├── make-selfsigned ├── mime-attach ├── mkca.py ├── mkca.rb ├── mkca.sh ├── mkcert.sh ├── mklinux ├── mkpasswd.c ├── mm ├── mpc-up ├── mutagen-ls ├── nextfile ├── nfreload ├── notify ├── obsolete │ ├── core-dns │ ├── fd │ ├── nbls │ ├── pkg │ ├── reconfigure │ ├── session-chooser │ ├── tag │ ├── unburst │ └── vram ├── pacman-verify ├── parse-snmp-engine-id ├── parseduid ├── pause.c ├── pdfcompress ├── perl-lspkgs ├── perl-packlist ├── perl-rebuild ├── perl-where ├── portblocktest ├── proctool.c ├── pylig ├── pyrebuild ├── rdap ├── rdt.c ├── rdt.py ├── rebuild-parttable.sh ├── reverse-ident ├── rg-copytags ├── rotate-laptop ├── rtf2html ├── rups ├── sendalert ├── shamerge ├── showsigmask.c ├── sign-exe ├── sign-xpi ├── sony-ericsson-screenshot ├── sparsemap ├── spawn.c ├── spectral-scan.sh ├── ssh-cipherscan ├── ssh2pem.util ├── ssh_force_lp.c ├── statx.c ├── strtool.c ├── svn-clone ├── sysrgba ├── systemd-lock-handler ├── tail-conntrack ├── tapchown.c ├── test-denettalk.txt ├── testrad ├── testrad.md ├── thunar-fm-proxy ├── timestamp ├── tla-clone ├── ubnt-airview ├── unborg ├── unescape.c ├── unhex.c ├── uniboxify ├── unsymlink.c ├── update-diskuse-cache ├── update-k5login ├── upower-ac-hold ├── upower-info ├── url-file-handler ├── urlencode.c ├── usbstatus ├── util.c ├── util.h ├── vbox ├── vi6tables ├── vici-get-remote-ip ├── vitables ├── weechat-fmtlogs.pl ├── weechat │ └── mpris2_np.py ├── wget-raw-archive.org ├── wigle2kml.awk ├── win32-cred.py ├── windows │ ├── df.py │ ├── dotnet.cmd │ ├── fingerd.py │ ├── hacks │ │ ├── From SNOW │ │ │ ├── login.py │ │ │ └── util.py │ │ ├── SetSystemPowerState.c │ │ ├── test-window-messages.py │ │ ├── tscon.py │ │ └── update-env-vars.cmd │ ├── identd │ │ ├── win32-identd.md │ │ └── win32-identd.py │ ├── make.cmd │ ├── monoff.cs │ ├── pathed.py │ ├── powermonitor │ │ ├── .gitignore │ │ ├── README.md │ │ ├── actions.py.example │ │ └── powermonitor.py │ ├── ts.py │ └── wts.py ├── wtmp_filter ├── xterm-color-chooser ├── xterm-color-chooser.png ├── zipdate ├── ziphash ├── ziprename └── zlib ├── mksrcinfo ├── motd ├── myip ├── n └── dns │ └── gssapi.py ├── netpath ├── notifysend ├── obj └── .empty ├── oci-console ├── on ├── onchange ├── osguess ├── pclip ├── pem2der ├── pildykbalance ├── psel ├── pull ├── puts ├── rcons ├── rconsole ├── rdo ├── rdp ├── rdt ├── recompress ├── rfc ├── rlisthosts ├── rlisthosts.py ├── rlocate ├── rmtdd ├── rmtodo ├── rpw ├── ruptime ├── setdns ├── setptr ├── setreverse ├── settitle ├── sftpipe ├── shoreplug ├── showcolors ├── showfile ├── spark ├── spawn ├── sprunge ├── srv ├── sshkeyupdate ├── subvols ├── swapusage ├── sx ├── sym ├── symgit ├── sysup ├── tapo ├── telnet ├── thirdparty ├── 256colors2.pl ├── SOURCE.txt ├── afs-audit-volumes ├── afs-get-versions ├── afs-vol-paths ├── apt-mark-minimum-manual.sh ├── bacman ├── chronic ├── desupout ├── desupout.go ├── desupout.pl ├── dnssec-dsfromdns ├── fsr ├── git-remote-hg ├── l ├── lsmounts ├── lsusb.py ├── natsort.c ├── peekvc.c ├── prename ├── strnatcmp.c ├── strnatcmp.h ├── tpm-show ├── vici.rb ├── wcwidth.c ├── webcheckout ├── writevt.c ├── xon └── zpipe.c ├── todo ├── tpm2_listpersistent ├── uksetptr ├── upload ├── utfvis ├── v ├── vim ├── vimdiff ├── vireverse ├── vis ├── vitodo ├── waitload ├── whatip ├── whatmac ├── whois4 ├── whois6 ├── wormhole ├── x509 ├── xcat ├── xtail └── yesterday /.gitignore: -------------------------------------------------------------------------------- 1 | obj/ 2 | *.pyc 3 | *.pyo 4 | -------------------------------------------------------------------------------- /.hostrun: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | # .hostrun -- wrapper to run compiled binaries from host-specific obj dirs 3 | exec -a ${0##*/} ~/bin/obj/host.$HOSTNAME/${0##*/} "$@" 4 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Mantas Mikulėnas 2 | Mantas Mikulėnas 3 | Mantas Mikulėnas 4 | -------------------------------------------------------------------------------- /@: -------------------------------------------------------------------------------- 1 | on -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License (also available at ) 2 | 3 | (c) 2010-2023 Mantas Mikulėnas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Projects moved to standalone repositories: 2 | 3 | * `certcheck` - https://github.com/grawity/tls-cert-check 4 | * `getpaste` - https://github.com/grawity/getpaste, https://git.nullroute.lt/hacks/getpaste.git/ 5 | * `git-annex-remote-gvfs` - https://git.nullroute.lt/cgit/hacks/git-annex-remote-gvfs.git/ 6 | * `mpris` - https://git.nullroute.lt/cgit/hacks/mpris.git/ 7 | * `simplehttpd` - https://git.nullroute.lt/hacks/php-simplehttpd.git/ 8 | * `treeify` - https://git.nullroute.lt/cgit/hacks/treeify.git/ 9 | -------------------------------------------------------------------------------- /asn1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # asn1 -- convenience wrapper for dumpasn1 3 | # 4 | # The dumpasn1 tool doesn't base64-decode input on its own, and won't 5 | # completely decode unseekable input such as stdin or pipes. 6 | 7 | . lib.bash || exit 8 | 9 | options=() 10 | inputs=() 11 | waitarg=0 12 | optend=0 13 | 14 | for arg; do 15 | if (( optend )); then 16 | inputs+=("$arg") 17 | elif (( waitarg )); then 18 | options+=("$arg") 19 | waitarg=0 20 | elif [[ $arg == -[cfwm] ]]; then 21 | options+=("$arg") 22 | waitarg=1 23 | elif [[ $arg == -- ]]; then 24 | options+=("$arg") 25 | optend=1 26 | elif [[ $arg == -[!-]* ]]; then 27 | options+=("$arg") 28 | elif [[ $arg == --help ]]; then 29 | dumpasn1 --help 30 | exit 0 31 | else 32 | inputs+=("$arg") 33 | fi 34 | done 35 | 36 | if (( ! ${#inputs[@]} )); then 37 | if [[ -t 0 ]]; then 38 | vdie "no input files" 39 | fi 40 | inputs+=("-") 41 | fi 42 | 43 | r=0 44 | for arg in "${inputs[@]}"; do 45 | tmp=() 46 | if [[ $arg == "-" ]]; then 47 | buf=$(mktemp /tmp/asn1.XXXXXXXX) 48 | tmp+=("$buf") 49 | cat > "$buf" 50 | arg=$buf 51 | fi 52 | if grep -qs "^-----" "$arg"; then 53 | raw=$(mktemp /tmp/asn1.XXXXXXXX) 54 | tmp+=("$raw") 55 | sed -n '/^-----BEGIN .*-----/,/^-----END .*-----/ { 56 | s/\r//g; /^[A-Za-z0-9+/=]*$/p 57 | }' "$arg" | base64 -d > "$raw" 58 | arg=$raw 59 | fi 60 | 61 | dumpasn1 "${options[@]}" -- "$arg" || r=1 62 | 63 | if (( ${#tmp[@]} )); then 64 | rm -f "${tmp[@]}" 65 | fi 66 | done 67 | exit $r 68 | -------------------------------------------------------------------------------- /asplog: -------------------------------------------------------------------------------- 1 | archlog -------------------------------------------------------------------------------- /bin/.signature: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # used by Evolution as a "signature script" 3 | 4 | exec cat ~/.signature 5 | -------------------------------------------------------------------------------- /bin/addr2names: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # addr2names -- look up hostnames for multiple IP addresses 3 | 4 | . lib.bash || exit 5 | 6 | verbose=0 7 | 8 | while getopts ":v" OPT; do 9 | case $OPT in 10 | v) verbose=1;; 11 | *) lib:die_getopts;; 12 | esac 13 | done; shift $((OPTIND-1)) 14 | 15 | for addr; do 16 | { 17 | name=$(addr2name "$addr") 18 | if [[ ! "$name" || "$name" == "$addr" ]]; then 19 | if (( verbose )); then 20 | name="-" 21 | else 22 | name="" 23 | fi 24 | fi 25 | if [[ "$name" ]]; then 26 | echo "$addr $name" 27 | fi 28 | } & 29 | done | natsort 30 | -------------------------------------------------------------------------------- /bin/annex-addplaceholder: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import requests 4 | import subprocess 5 | 6 | ua = requests.Session() 7 | 8 | def get_url_size(url): 9 | global ua 10 | r = ua.head(url) 11 | r.raise_for_status() 12 | s = r.headers["Content-Length"] 13 | return int(s) 14 | 15 | def parse_hashfile(name): 16 | with open(name, "r") as fh: 17 | for line in fh: 18 | line = line.strip().split(" ", 1) 19 | if len(line) == 2 and len(line[0]) == 64 and line[1][0] in " *": 20 | yield (line[0], line[1][1:]) 21 | 22 | urlbase = 'http://mirror.duomenucentras.lt/centos/5.11/isos/x86_64/' 23 | hashfile = 'CentOS-5.11-x86_64-sha256sum.txt.asc' 24 | 25 | wanted = { 26 | "CentOS-5.11-x86_64-bin-DVD-1of2.iso", 27 | } 28 | 29 | for hash, basename in parse_hashfile(hashfile): 30 | if basename not in wanted: 31 | continue 32 | 33 | url = "%s/%s" % (urlbase, basename) 34 | size = get_url_size(url) 35 | 36 | ext = basename.split(".")[-1] 37 | key = 'SHA256E-s%d--%s.%s' % (size, hash, ext) 38 | 39 | print("creating fake link for %s" % key) 40 | 41 | os.symlink(".git/annex/objects/xx/yy/%s" % key, basename) 42 | 43 | subprocess.call(["git", "annex", "add", basename]) 44 | 45 | subprocess.call(["git", "annex", "addurl", 46 | "--fast", 47 | "--file=%s" % basename, 48 | url]) 49 | 50 | subprocess.call(["git", "annex", "fsck", basename]) 51 | -------------------------------------------------------------------------------- /bin/annex-dupes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # vim: ts=4 sw=4 et 3 | export MIN_BYTES=512 4 | annex find --format='${key} ${file}\n' --include '*' "$@" | 5 | perl -E ' 6 | sub fmt_key { 7 | my ($key) = @_; 8 | #return "\e[m$key\e[m"; 9 | return (-t STDOUT) ? "\e[38;5;208m$key\e[m" : "$key"; 10 | } 11 | sub fmt_path { 12 | my ($path) = @_; 13 | my ($head, $tail) = ($path =~ m!^(.+)/(.+?)$!); 14 | $head //= "."; 15 | $tail //= $path; 16 | return (-t STDOUT) ? "$head/\e[2m$tail\e[m" : "$head/$tail"; 17 | } 18 | my $min = int($ENV{MIN_BYTES} // "0"); 19 | my %keys; 20 | while (<>) { 21 | chomp; 22 | my ($key, $file) = split(/ /, $_, 2); 23 | next if $min && ($key =~ /-s(\d+)--/) && ($1 < $min); 24 | push @{$keys{$key}}, $file; 25 | } 26 | for my $key (sort {$keys{$a}[0] cmp $keys{$b}[0]} keys %keys) { 27 | my @files = @{$keys{$key}}; 28 | if (@files > 1) { 29 | print fmt_key($key), "\n"; 30 | print " ", fmt_path($_), "\n" for sort @files; 31 | print "\n"; 32 | } 33 | } 34 | ' 35 | -------------------------------------------------------------------------------- /bin/annex-format-log: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # Format git-annex:*.log 3 | # vim: ts=4 sw=4 et 4 | use List::MoreUtils qw(uniq); 5 | 6 | %items = (); 7 | @items = (); 8 | while (<>) { 9 | chomp; 10 | my ($key, $value, $time) = /^(\S+) (.*) timestamp=([0-9.]+)s$/; 11 | if (!$items{$key}) { 12 | push @items, $key; 13 | $items{$key} //= []; 14 | } 15 | push @{$items{$key}}, [$time, $value, $_]; 16 | } 17 | for my $key (@items) { 18 | my @items = uniq 19 | map {"(".$_->[0].") ".$_->[1]} 20 | grep {$_->[1] =~ /./} 21 | sort {$a->[0] <=> $b->[0]} 22 | @{$items{$key}}; 23 | my $last = pop @items; 24 | print "\e[1m$key\e[m\n"; 25 | print " - $_\n" for $last; 26 | print " \e[38;5;242m- $_\e[m\n" for reverse @items; 27 | print "\n"; 28 | } 29 | -------------------------------------------------------------------------------- /bin/annex-store: -------------------------------------------------------------------------------- 1 | annex-dup -------------------------------------------------------------------------------- /bin/borgdf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Originally by elho 3 | 4 | repo=$1 5 | 6 | printf 'Archive\t\t\t\t\tOrig\tComp\tDedup\n' 7 | printf '%-32.32s\t%s\t%s\t%s\n' $(borg info --json --sort-by name --glob-archives '*' "$repo" | jq '.archives[] | "\(.name) \(.stats.original_size) \(.stats.compressed_size) \(.stats.deduplicated_size)"' | sed --expression='s/^"//;s/"$//' | numfmt --field='2-4' --to=iec) 8 | -------------------------------------------------------------------------------- /bin/cachedir-tag: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | user=${USER:-${LOGNAME:-$(whoami)}} 4 | host=${HOSTNAME:-$(hostname)} 5 | app="$user@$host" 6 | 7 | if [ "$1" = "-a" ]; then 8 | app="$2 ($app)"; shift 2 9 | fi 10 | 11 | str="Signature: 8a477f597d28d172789f06886806bc55 12 | # This file is a cache directory tag created by $app. 13 | # For information about cache directory tags, see: 14 | # http://www.brynosaurus.com/cachedir/" 15 | 16 | if [ $# -eq 0 ]; then 17 | echo "Usage: cachedir-tag [-a ] ..." 18 | exit 2 19 | fi 20 | 21 | err=0 22 | 23 | for dir; do 24 | if echo "$str" > "$dir/CACHEDIR.TAG"; then 25 | echo "Tagged $dir" 26 | else 27 | err=1 28 | fi 29 | done 30 | 31 | exit $err 32 | -------------------------------------------------------------------------------- /bin/cap-upload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | upload -q -c -0 -d cap -S 's/\.temp//' "$@" 3 | -------------------------------------------------------------------------------- /bin/capsled: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # capsled -- blink the Caps Lock LED 3 | # 4 | # (Avoid lib.bash as this is often called from /root/.profile or such.) 5 | 6 | usage() { 7 | echo "Usage: ${0##*/} [count]" 8 | echo 9 | echo "By default, the LED returns to original state after blinking." 10 | echo "Suffixing count with + disables this." 11 | } 12 | 13 | shopt -s nullglob 14 | 15 | n=${1:-1} # number of blinks 16 | t_on=${2:-0.1} # on duration 17 | t_off=${3:-0.1} # off duration 18 | restore=1 # whether to return back to original state 19 | 20 | if [[ $n == *+ ]]; then 21 | n=${n%+} 22 | restore=0 23 | fi 24 | 25 | declare -a paths=(/sys/class/leds/*::capslock/brightness) 26 | declare -A saved=() 27 | 28 | do_restore() { 29 | for led in "${paths[@]}"; do 30 | echo ${saved[$led]-0} > $led 31 | done 32 | } 33 | 34 | do_save() { 35 | for led in "${paths[@]}"; do 36 | saved[$led]=$(< $led) 37 | done 38 | } 39 | 40 | if (( ! ${#paths[@]} )); then 41 | exit 42 | fi 43 | 44 | do_save 45 | trap 'do_restore; exit' INT QUIT 46 | max=$(( n*2 + restore )) 47 | for (( i=1; i < max; i++ )); do 48 | for led in "${paths[@]}"; do 49 | echo $(( (i + saved[$led]) % 2 )) > $led 50 | done 51 | if (( i+1 == max )); then 52 | break 53 | elif (( i % 2 )); then 54 | sleep $t_on 55 | else 56 | sleep $t_off 57 | fi 58 | done 59 | if (( restore )); then 60 | do_restore 61 | fi 62 | -------------------------------------------------------------------------------- /bin/catznip: -------------------------------------------------------------------------------- 1 | wrappers/catznip -------------------------------------------------------------------------------- /bin/cdrip: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | image=$1; shift 6 | device=/dev/sr0 7 | 8 | if [[ ! $image ]]; then 9 | die "image name not specified" 10 | elif [[ $image == -* ]]; then 11 | die "any options must be specified after image name" 12 | elif [[ $image != *.iso ]]; then 13 | image+=".iso" 14 | fi 15 | 16 | logfile=${image/%.iso/.log} 17 | 18 | if [[ -s $logfile ]]; then 19 | info "resuming copy to '$image'" 20 | if ddrescuelog -D "$logfile"; then 21 | warn "log is marked as 'finished', but retrying anyway" 22 | fi 23 | else 24 | info "copying to '$image'" 25 | fi 26 | 27 | debug "checking if SCSI device is ready" 28 | if [[ ! -b $device ]]; then 29 | die "device '$device' does not exist (not connected?)" 30 | fi 31 | if ! sg_turs -p "$device"; then 32 | info "waiting for device to become ready" 33 | until sg_turs -p "$device"; do 34 | sleep 0.3 35 | done 36 | fi 37 | 38 | debug "creating image using ddrescue" 39 | ddrescue "$device" "$image" "$logfile" "$@" || exit 40 | 41 | debug "ejecting '$device'" 42 | eject "$device" 43 | 44 | if ddrescuelog -D "$logfile"; then 45 | info "copy was successful" 46 | ddrescuelog -dv "$logfile" 47 | else 48 | warn "copy failed, wipe the CD clean and use --rescrape" 49 | fi 50 | -------------------------------------------------------------------------------- /bin/cron.dropbatch: -------------------------------------------------------------------------------- 1 | ../misc/cron.dropbatch -------------------------------------------------------------------------------- /bin/cronjob: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # cronjob -- wrapper for cron jobs to set common environment 3 | 4 | test "$XDG_RUNTIME_DIR" || export XDG_RUNTIME_DIR="/run/user/$(id -u)" 5 | test "$SSH_AUTH_SOCK" || export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent" 6 | 7 | . ~/.dotfiles/environ || exit 8 | 9 | chronic='chronic' 10 | useshell=0 11 | krbcc=0 12 | waitnet=0 13 | 14 | while getopts 'cknv' OPT; do 15 | case $OPT in 16 | c) useshell=1;; 17 | k) krbcc=1;; 18 | n) waitnet=1;; 19 | v) chronic="";; 20 | \?) exit 2;; 21 | esac 22 | done; shift $((OPTIND-1)) 23 | 24 | if (( ! $# )); then 25 | echo "$0: no command given" >&2 26 | exit 2 27 | fi 28 | 29 | if (( useshell )); then 30 | set -- sh -c "$*" 31 | fi 32 | 33 | if (( krbcc )); then 34 | export KRB5CCNAME="FILE:/tmp/krb5cc_$(id -u)_cron" 35 | export KRB5_CLIENT_KTNAME="FILE:$HOME/.config/cron.keytab" 36 | fi 37 | 38 | if (( waitnet )); then 39 | nm-online -qx || exit 0 40 | fi 41 | 42 | nice $chronic "$@" 43 | -------------------------------------------------------------------------------- /bin/dataurl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | usage() { 6 | echo "Usage: $progname [-t TYPE] FILE..." 7 | echo 8 | echo_opt "-t TYPE" "override guessed MIME type" 9 | } 10 | 11 | opt_mime= 12 | 13 | while getopts :t: OPT; do 14 | case $OPT in 15 | t) opt_mime=$OPTARG;; 16 | *) lib:die_getopts;; 17 | esac 18 | done; shift $[OPTIND-1] 19 | 20 | if (( ! $# )); then 21 | vdie "no file specified" 22 | fi 23 | 24 | for file; do 25 | mime=${opt_mime:-"$(file --brief --mime-type "$file")"} 26 | data=$(base64 --wrap=0 "$file") 27 | echo "data:$mime;base64,$data" 28 | done 29 | -------------------------------------------------------------------------------- /bin/dd: -------------------------------------------------------------------------------- 1 | wrappers/dd -------------------------------------------------------------------------------- /bin/dnssec-dsfromdns: -------------------------------------------------------------------------------- 1 | ../thirdparty/dnssec-dsfromdns -------------------------------------------------------------------------------- /bin/domainsort: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # domainsort -- sort a list of DNS domains right-to-left 3 | 4 | print for 5 | map { "$_\n" } 6 | map { $_->[0] } 7 | sort { $a->[1] cmp $b->[1] } 8 | map { [$_, join(".", reverse split(/\./, $_))] } 9 | map { s/[\r\n]//gr } 10 | <>; 11 | -------------------------------------------------------------------------------- /bin/emergency-su: -------------------------------------------------------------------------------- 1 | /usr/bin/emergency-su -------------------------------------------------------------------------------- /bin/expandzones: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Expand a CIDR prefix into a list of rDNS zone names 3 | 4 | expand() { 5 | local name=$1 6 | if [[ $name == */* ]]; then 7 | local addr plen tail over 8 | local nbits lbits tfmt 9 | addr=${name%/*} 10 | plen=${name#*/} 11 | name=$(arpaname "$addr") || { 12 | echo "error: '$addr/$plen' is not an IP network" >&2 13 | return 14 | } 15 | name=${name,,} 16 | if [[ $addr == *:* ]]; then 17 | nbits=128 lbits=4 tfmt=%x 18 | else 19 | nbits=32 lbits=8 tfmt=%d 20 | fi 21 | over=$(( plen % lbits )) 22 | if (( exact && over )); then 23 | echo "error: '$addr/$plen' cannot be delegated directly" >&2 24 | return 25 | fi 26 | for (( n = nbits; n > plen; n -= lbits )); do 27 | tail=${name%%.*} 28 | name=${name#*.} 29 | done 30 | if (( over )); then 31 | local nmask smask first last 32 | if [[ $tfmt == %x ]]; then 33 | tail=$(( 16#$tail )) 34 | fi 35 | nmask=$(( (1 << lbits) - 1 )) 36 | smask=$(( (nmask << lbits >> over) & nmask )) 37 | first=$(( tail & (smask & nmask) )) 38 | last=$(( tail | (~smask & nmask) )) 39 | for (( t = first; t <= last; t++ )); do 40 | printf "$tfmt.%s\n" "$t" "$name" 41 | done 42 | else 43 | echo "$name" 44 | fi 45 | else 46 | echo "$name" 47 | fi 48 | } 49 | 50 | if (( $# )); then 51 | for name; do 52 | expand "$name" 53 | done 54 | else 55 | while read -r name rest; do 56 | expand "$name" 57 | done 58 | fi 59 | -------------------------------------------------------------------------------- /bin/ffconcat: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | inputs=() 6 | args=(-c copy) 7 | argmode=0 8 | 9 | for arg; do 10 | if [[ $arg == "--" ]]; then 11 | (( ++argmode )); 12 | elif (( argmode == 0 )); then 13 | if [[ ! -e "$arg" ]]; then 14 | err "'$arg' is not a file" 15 | continue 16 | fi 17 | arg=$(readlink -f "$arg") 18 | inputs+=("$arg") 19 | elif (( argmode >= 1 )); then 20 | args+=("$arg") 21 | fi 22 | done 23 | 24 | if (( argmode == 0 )); then 25 | err "did you forget to specify '--' and an output file?" 26 | fi 27 | 28 | ((!errors)) || exit 29 | 30 | ffmpeg -safe 0 -f concat -i <(printf "file '%s'\n" "${inputs[@]}") "${args[@]}" 31 | -------------------------------------------------------------------------------- /bin/ffmpeg: -------------------------------------------------------------------------------- 1 | wrappers/ffmpeg -------------------------------------------------------------------------------- /bin/ffplay: -------------------------------------------------------------------------------- 1 | wrappers/ffmpeg -------------------------------------------------------------------------------- /bin/ffprobe: -------------------------------------------------------------------------------- 1 | wrappers/ffmpeg -------------------------------------------------------------------------------- /bin/find-computer-name: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # get-computer-name -- Extract the computer name out of a mounted Windows partition 3 | # 4 | # Depends on `reged` from the 'chntpw' package. 5 | 6 | . lib.bash || exit 7 | 8 | for root; do 9 | root="${root%/}" 10 | 11 | # Case-insensitive search 12 | for name in 'Windows' 'System32' 'config' 'SYSTEM'; do 13 | debug "lookup '$name' in '$root'" 14 | next=$(find "$root" -mindepth 1 -maxdepth 1 -iname "$name") && 15 | [[ $next ]] || 16 | die "path '$root/$name' not found" 17 | root=$next 18 | done 19 | 20 | [[ -f $root ]] || die "hive '$root' not a regular file" 21 | 22 | echo "reading '$root'" 23 | 24 | reged -x "$root" \ 25 | 'HKEY_LOCAL_MACHINE\SYSTEM' \ 26 | '\ControlSet001\Control\ComputerName\ComputerName' \ 27 | /dev/stdout |& 28 | grep -i '"ComputerName"' 29 | done 30 | -------------------------------------------------------------------------------- /bin/find-glyph: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | char=$1 4 | font=$2 5 | 6 | FC_DEBUG=4 pango-view --font="$font" --text="$char" -q 2>&1 | awk -F\" '/family: /{m=$2} END{print m}' 7 | -------------------------------------------------------------------------------- /bin/find-setuid: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | _find() { find "$@" -type f -perm /u+s,g+s -ls; } 3 | 4 | if [ $# -gt 0 ]; then 5 | _find "$@" 6 | else 7 | _find /{,usr/}{bin,sbin,lib} 8 | fi 9 | -------------------------------------------------------------------------------- /bin/findbroken: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # findbroken -- list broken symlinks 3 | 4 | if [ -t 1 ]; then 5 | fmt="%p \033[38;5;4m=>\033[m \033[38;5;9m%l\033[m\n" 6 | else 7 | fmt="%p => %l\n" 8 | fi 9 | 10 | find "$@" -xtype l -printf "$fmt" 11 | -------------------------------------------------------------------------------- /bin/firestorm: -------------------------------------------------------------------------------- 1 | wrappers/firestorm -------------------------------------------------------------------------------- /bin/fontview: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # fontview - default parameters for pango-view 3 | 4 | file=~/Attic/Misc/2019/CrimePuzzlement.txt 5 | 6 | pango-view --width=500 --wrap=word <(head -${lines:-15} "$file") "$@" 7 | -------------------------------------------------------------------------------- /bin/funsync: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # funsync -- run a program with fsync() disabled 3 | 4 | if [ ! "$_FUNSYNC" ]; then 5 | lib=$(which libfunsync.so 2>/dev/null) 6 | 7 | if [ "$lib" ]; then 8 | export LD_PRELOAD=${LD_PRELOAD}${LD_PRELOAD:+:}$lib 9 | else 10 | echo "$0: warning: libfunsync.so not found" >&2 11 | fi 12 | 13 | export _FUNSYNC=1 14 | fi 15 | 16 | exec "$@" 17 | -------------------------------------------------------------------------------- /bin/genmac: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # genmac -- generate a MAC address and display in several formats 3 | 4 | my @bytes = map {int rand 256} 1..6; 5 | 6 | $bytes[0] &= ~1; # clear "unicast/group" bit 7 | $bytes[0] |= 2; # set "global/local" bit 8 | 9 | print join(":", map {sprintf "%02X", $_} @bytes), "\n"; 10 | -------------------------------------------------------------------------------- /bin/git-mirror: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # git mirror -- clone a Git repository in "mirror branches" configuration 3 | # 4 | # Unlike `git clone --mirror`, this tool only clones remote branches (and 5 | # associated tags) but not any other refs, e.g. no GitHub/GitLab pull-request 6 | # heads. 7 | # 8 | # Previously this could be simplified to: 9 | # 10 | #git clone --bare --config remote.origin.fetch='+refs/heads/*:refs/heads/*' "$@" 11 | # 12 | # However, with Git 2.21 this no longer works and results in "fatal: multiple 13 | # updates for ref '' not allowed". 14 | 15 | . lib.bash || exit 16 | 17 | while (( $# )); do 18 | url=$1; shift 19 | if [[ $url != *:* ]]; then 20 | die "expected repository URL, got '$url' instead" 21 | fi 22 | 23 | if [[ $1 != */* ]]; then 24 | dir=$1; shift 25 | fi 26 | 27 | if [[ $dir && $dir != *.git ]]; then 28 | dir+=.git 29 | fi 30 | 31 | if [[ ! $dir ]]; then 32 | tmp=$url 33 | while [[ $tmp == */ ]]; do tmp=${tmp%/}; done 34 | tmp=${tmp%.git} 35 | while [[ $tmp == */ ]]; do tmp=${tmp%/}; done 36 | tmp=${tmp##*/} 37 | dir=$tmp.git 38 | info "cloning to '$dir'" 39 | fi 40 | 41 | if [[ -e $dir ]]; then 42 | err "target '$dir' already exists" 43 | continue 44 | fi 45 | 46 | git init --bare "$dir" && 47 | git -C "$dir" remote add origin "$url" && 48 | git -C "$dir" config remote.origin.fetch "+refs/heads/*:refs/heads/*" && 49 | git -C "$dir" remote update 50 | done 51 | 52 | ((!errors)) 53 | -------------------------------------------------------------------------------- /bin/git-show-merge: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # git show-merge -- list commits part of a specified merge 3 | 4 | range="$1^..$1" 5 | 6 | if [ -t 1 ]; then 7 | tig "$range" 8 | else 9 | git log --graph "$range" 10 | fi 11 | -------------------------------------------------------------------------------- /bin/git-show-replaced: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # git show-replaced -- list differences between original and "replaced" objects 3 | 4 | . lib.bash || exit 5 | 6 | objects=$* 7 | 8 | if [[ ! $objects ]]; then 9 | objects=$(git replace --list) 10 | fi 11 | 12 | for object in $objects; do 13 | diff -u \ 14 | --color \ 15 | --label "o/$object" \ 16 | --label "r/$object" \ 17 | <(git --no-replace-objects cat-file -p "$object") \ 18 | <(git cat-file -p "$object") \ 19 | || true 20 | done 21 | -------------------------------------------------------------------------------- /bin/git-tag-v-all: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # git tag-v-all -- invoke `git tag -v` for all tags 3 | # 4 | # This can be used to build up GnuPG's "Trust on first use" database. 5 | 6 | . lib.bash || exit 7 | 8 | thin=0 9 | unsigned=0 10 | failed=0 11 | verified=0 12 | 13 | for tag in $(git tag); do 14 | if [[ $(git cat-file -t "refs/tags/$tag") != tag ]]; then 15 | debug "tag '$tag' is thin" 16 | (( ++thin )) 17 | continue 18 | fi 19 | if ! git cat-file tag "refs/tags/$tag" | grep -qs "BEGIN PGP SIGNATURE"; then 20 | debug "tag '$tag' is not signed" 21 | (( ++unsigned )) 22 | continue 23 | fi 24 | log2 "$tag" 25 | if git --no-pager tag -v "$tag"; then 26 | : 27 | else 28 | err "verification failed ($?)" 29 | (( ++failed )) 30 | continue 31 | fi 32 | (( ++verified )) 33 | done 34 | 35 | info "$verified ok, $failed failed, $unsigned unsigned, $thin thin" 36 | 37 | if (( failed )); then 38 | warn "$failed signatures failed to verify" 39 | exit 1 40 | fi 41 | -------------------------------------------------------------------------------- /bin/gpg-get-missing: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | gpg --with-colons --list-sigs "$@" | { 4 | declare -A todo=() 5 | while IFS=: read -r type _ _ _ id _ _ _ _ uid _; do 6 | if [[ $type == sig ]]; then 7 | if [[ $uid == *User\ ID\ not\ found* ]]; then 8 | echo "- [$id] $uid" 9 | todo[$id]=1 10 | else 11 | echo "+ [$id] $uid" 12 | fi 13 | fi 14 | done 15 | echo "recv ${!todo[@]}" 16 | gpg --recv-keys "${!todo[@]}" 17 | } 18 | -------------------------------------------------------------------------------- /bin/gpg-protect-tool: -------------------------------------------------------------------------------- 1 | /usr/lib/gnupg/gpg-protect-tool -------------------------------------------------------------------------------- /bin/gpg-test-import: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | GNUPGHOME=$(mktemp -d /tmp/gpg.XXXXXXXXXX) 6 | export GNUPGHOME 7 | 8 | info "importing from stdin" 9 | gpg --import || exit 10 | 11 | gpg --with-colons --list-keys | 12 | awk -F: '/^(pub|sub):/ {print $5, $12}' | 13 | while read id usage; do 14 | case $usage in 15 | *s*) 16 | info "testing signing with $id" 17 | date | gpg -u "$id!" --sign | gpg --trust-model always --verify 18 | ;;& 19 | *e*) 20 | info "testing encryption with $id" 21 | date | gpg -r "$id!" --trust-model always --encrypt | gpg --decrypt 22 | ;;& 23 | *a*) 24 | info "testing authentication with $id" 25 | lib:crash "auth testing not implemented" 26 | ;;& 27 | *c*) 28 | info "testing certification with $id" 29 | testuid=test.$$.$RANDOM$RANDOM$RANDOM 30 | gpg --batch --pinentry-mode loopback --passphrase "" --quick-gen-key "$testuid" 31 | gpg --batch --yes -u "$id!" --lsign-key "$testuid" 32 | ;;& 33 | esac 34 | done 35 | 36 | rm -rf "$GNUPGHOME" 37 | -------------------------------------------------------------------------------- /bin/gpg-unprotect: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | GNUPGHOME=$(mktemp -d /tmp/gpg.XXXXXXXXXX) 6 | export GNUPGHOME 7 | 8 | info "importing from stdin" >&2 9 | gpg --import || exit 10 | 11 | info "unprotecting all secret keys" >&2 12 | unset pass 13 | for key in "$GNUPGHOME"/private-keys-v1.d/*.key; do 14 | while true; do 15 | if [[ ! $pass ]]; then 16 | read -s -p "Passphrase: " pass < /dev/tty >&2 && echo >&2 17 | fi 18 | if gpg-protect-tool -P "$pass" -u < "$key" > "$key.new"; then 19 | log "unprotected $key" >&2 20 | mv "$key.new" "$key" 21 | break 22 | else 23 | err "passphrase appears to be incorrect" 24 | unset pass 25 | fi 26 | done 27 | done 28 | #gpg-connect-agent "keyinfo --list" /bye | 29 | # awk '/^S KEYINFO / {print $3}' | 30 | # while read keygrip; do 31 | # info "unprotecting &$keygrip" 32 | # gpg-connect-agent "passwd $keygrip" /bye 33 | # done 34 | 35 | info "exporting to stdout" >&2 36 | gpg --armor --export 37 | gpg --armor --export-secret-keys 38 | 39 | info "cleaning up" >&2 40 | rm -rf "$GNUPGHOME" 41 | -------------------------------------------------------------------------------- /bin/gumount: -------------------------------------------------------------------------------- 1 | gmount -------------------------------------------------------------------------------- /bin/hlsrip: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | from nullroute.scrape import Scraper 4 | import requests 5 | import os 6 | import time 7 | 8 | class HlsRipper(Scraper): 9 | def rip(self, hls_url): 10 | base = os.path.dirname(hls_url) 11 | while True: 12 | resp = self.ua.get(hls_url) 13 | for line in resp.content.splitlines(): 14 | if line.startswith(b"#"): 15 | continue 16 | else: 17 | segment = line.decode() 18 | if not os.path.exists(segment): 19 | print(segment) 20 | seg_url = os.path.join(base, segment) 21 | self.save_file(seg_url, segment, progress=True) 22 | time.sleep(1) 23 | 24 | parser = argparse.ArgumentParser() 25 | parser.add_argument("hls_url", 26 | help="HLS M3U8 playlist URL") 27 | args = parser.parse_args() 28 | 29 | hr = HlsRipper() 30 | hr.rip(args.hls_url) 31 | -------------------------------------------------------------------------------- /bin/imv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # imv -- interactive mv 3 | 4 | . lib.bash || exit 5 | 6 | interactive_mv() { 7 | local old=$1 8 | local new=$2 9 | echo "Old: $old" 10 | read -p "New: " -e -i "$new" new 11 | if [[ "$old" != "$new" ]]; then 12 | mv -v -i "$old" "$new" 13 | fi 14 | } 15 | 16 | if (( $# < 1 )); then 17 | old=$(psel) 18 | if [[ ! -e $old ]]; then 19 | die "no arguments and no file name in current selection" 20 | fi 21 | fi 22 | 23 | if (( $# < 2 )); then 24 | old=$1 25 | if [[ -e $old ]]; then 26 | interactive_mv "$old" "$old" 27 | else 28 | old=$(psel) 29 | new=$1 30 | info "guessing old name '$old' from selection" 31 | if [[ ! -e $old ]]; then 32 | die "old name doesn't exits" 33 | else 34 | interactive_mv "$old" "$new" 35 | fi 36 | fi 37 | fi 38 | 39 | if (( $# >= 2 )); then 40 | mv -v -i "$@" 41 | fi 42 | -------------------------------------------------------------------------------- /bin/interval: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | sub int2time { 4 | my $int = shift // return "∞"; 5 | 6 | $int = abs int($int); 7 | $int -= my $s = $int % 60; $int /= 60; 8 | $int -= my $m = $int % 60; $int /= 60; 9 | $int -= my $h = $int % 24; $int /= 24; 10 | $int -= my $d = $int % 7; $int /= 7; 11 | $int -= my $w = $int; 12 | 13 | my @fmt; 14 | my @arg; 15 | 16 | if ($w or @arg) { push @fmt, "%dw"; push @arg, $w; } 17 | if ($d or @arg) { push @fmt, "%dd"; push @arg, $d; } 18 | if ($h or @arg) { push @fmt, "%dh"; push @arg, $h; } 19 | if (!$w) { push @fmt, "%dm"; push @arg, $m; } 20 | if (!$w) { push @fmt, "%ds"; push @arg, $s; } 21 | 22 | return sprintf("@fmt", @arg); 23 | } 24 | 25 | my $str = int2time(shift @ARGV); 26 | 27 | print "$str\n"; 28 | -------------------------------------------------------------------------------- /bin/ip-autoconf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import ipaddress 3 | import sys 4 | 5 | def parse_mac(mac): 6 | if ":" in mac: 7 | mac = mac.split(":") 8 | mac = [int(c, 16) for c in mac] 9 | elif "-" in mac: 10 | mac = mac.split("-") 11 | mac = [int(c, 16) for c in mac] 12 | else: 13 | raise ValueError("%r is not a recognized MAC address" % mac) 14 | 15 | return mac 16 | 17 | def maybe_net(arg): 18 | return ("/" in arg) or arg.endswith(":") 19 | 20 | args = sys.argv[1:] 21 | mac = net = None 22 | if len(args) == 1: 23 | mac, = args 24 | net = "fe80::/64" 25 | elif len(args) == 2: 26 | if maybe_net(args[0]): 27 | net, mac = args 28 | elif maybe_net(args[1]): 29 | mac, net = args 30 | 31 | if (mac is None) or (net is None): 32 | exit("Usage: ip-autoconf ") 33 | 34 | if "/" not in net: 35 | net += "/64" 36 | elif not net.endswith("/64"): 37 | exit("only /64 networks support autoconfiguration") 38 | 39 | try: 40 | net = ipaddress.IPv6Network(net) 41 | except ValueError as e: 42 | exit("invalid IPv6 prefix: %s" % e) 43 | 44 | try: 45 | mac = parse_mac(mac) 46 | except ValueError: 47 | exit("invalid MAC address given") 48 | 49 | prefix = net.network_address.packed[:8] 50 | suffix = [*mac[:3], 0xFF, 0xFE, *mac[3:]] 51 | suffix[0] ^= 2 52 | 53 | addr = bytes(prefix) + bytes(suffix) 54 | addr = ipaddress.IPv6Address(addr) 55 | print(addr) 56 | -------------------------------------------------------------------------------- /bin/ip-summarize: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # ip-summarize - print summarized CIDR masks for a given IP address range 3 | import argparse 4 | import ipaddress 5 | 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument("first_addr") 8 | parser.add_argument("last_addr") 9 | args = parser.parse_args() 10 | 11 | try: 12 | first = ipaddress.ip_address(args.first_addr) 13 | last = ipaddress.ip_address(args.last_addr) 14 | ranges = ipaddress.summarize_address_range(first, last) 15 | for net in ranges: 16 | print(net) 17 | except ValueError as e: 18 | exit("error: %s" % (e,)) 19 | -------------------------------------------------------------------------------- /bin/json2json: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/json2toml: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/json2yaml: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/kc: -------------------------------------------------------------------------------- 1 | ../kerberos/kc -------------------------------------------------------------------------------- /bin/kc.sh: -------------------------------------------------------------------------------- 1 | ../kerberos/kc.sh -------------------------------------------------------------------------------- /bin/kl: -------------------------------------------------------------------------------- 1 | ../kerberos/kl -------------------------------------------------------------------------------- /bin/kokua: -------------------------------------------------------------------------------- 1 | wrappers/kokua -------------------------------------------------------------------------------- /bin/kzgrep: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # kzgrep - grep the current kernel config file 3 | 4 | . lib.bash || exit 5 | 6 | case $(uname) in 7 | Linux) 8 | config=/proc/config.gz 9 | if [[ ! -e "$config" ]]; then 10 | version=$(uname -r) 11 | debug "no $config, looking in /boot for $version" 12 | config=/boot/config-$version 13 | fi 14 | if [[ ! -e "$config" ]]; then 15 | die "could not find kernel config" 16 | fi 17 | debug "kconfig file is \"$config\"" 18 | zgrep -i "$@" "$config" 19 | ;; 20 | FreeBSD) 21 | sysctl kern.conftxt | grep -i "$@" 22 | ;; 23 | *) 24 | die "unknown OS '$(uname)'" 25 | ;; 26 | esac 27 | -------------------------------------------------------------------------------- /bin/ldifunwrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # unwrap LDIF files 3 | import argparse 4 | import base64 5 | import sys 6 | 7 | def xprint(buf, decode=False): 8 | if decode and ": " in buf: 9 | k, v = buf.split(": ", 1) 10 | if k.endswith(":"): 11 | try: 12 | v = base64.b64decode(v).decode() 13 | except UnicodeDecodeError: 14 | pass 15 | else: 16 | k = k[:-1] 17 | buf = "%s: %s" % (k, v) 18 | print(buf) 19 | 20 | parser = argparse.ArgumentParser() 21 | parser.add_argument("-d", "--decode", action="store_true", 22 | help="Base64-decode fields that are valid UTF-8") 23 | args = parser.parse_args() 24 | opts = {"decode": args.decode} 25 | 26 | buf = "" 27 | for line in sys.stdin: 28 | line = line.rstrip("\r\n") 29 | if line.startswith(" "): 30 | buf += line[1:] 31 | else: 32 | xprint(buf, **opts) 33 | buf = line 34 | if buf: 35 | xprint(buf, **opts) 36 | -------------------------------------------------------------------------------- /bin/lsusb.py: -------------------------------------------------------------------------------- 1 | ../thirdparty/lsusb.py -------------------------------------------------------------------------------- /bin/mac2ll: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # mac2ll -- convert MAC addresses to IPv6 link-local addresses 3 | import argparse 4 | import ipaddress 5 | import re 6 | import sys 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument("mac_address", nargs="+") 10 | args = parser.parse_args() 11 | 12 | for mac in args.mac_address: 13 | mac = re.split("[:-]", mac) 14 | mac = [int(x, 16) for x in mac] 15 | mac[0] ^= 2 16 | addr = [0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] \ 17 | + mac[:3] + [0xFF, 0xFE] + mac[3:] 18 | addr = bytes(addr) 19 | addr = ipaddress.IPv6Address(addr) 20 | print(addr) 21 | -------------------------------------------------------------------------------- /bin/mkwindowsurl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # mkwindowsurl -- create a .URL "Internet Shortcut" for Windows 3 | import argparse 4 | 5 | parser = argparse.ArgumentParser() 6 | parser.add_argument("-f", "--force", action="store_true", 7 | help="overwrite existing files") 8 | parser.add_argument("url", 9 | help="destination URL") 10 | parser.add_argument("file", 11 | help="shortcut file (suffixed .url)") 12 | args = parser.parse_args() 13 | 14 | if not args.file.upper().endswith(".URL"): 15 | args.file += ".URL" 16 | 17 | with open(args.file, "w" if args.force else "x") as fh: 18 | fh.write("[InternetShortcut]\r\n") 19 | fh.write("URL=%s\r\n" % args.url) 20 | 21 | print("Shortcut %r created." % args.file) 22 | -------------------------------------------------------------------------------- /bin/mosh-detach: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # mosh-detach -- kill detached Mosh servers 3 | import argparse 4 | from nullroute.system.utmp import enum_utmp, UtType 5 | import re 6 | import subprocess 7 | 8 | def hup(tty): 9 | res = subprocess.call(["pkill", "-HUP", "-t", tty]) 10 | if res != 0: 11 | # Probably an entry that was just hup'd recently and its mosh-server is 12 | # still in the process of exiting. 13 | print("could not hup line %s (likely a stale entry)" % tty) 14 | 15 | parser = argparse.ArgumentParser() 16 | parser.description = "Hang up all terminals belonging to detached Mosh servers." 17 | parser.add_argument("-n", "--dry-run", 18 | action="store_true", 19 | help="only print ttys that would be hung up") 20 | parser.add_argument("-q", "--quiet", 21 | action="store_true", 22 | help="print nothing") 23 | args = parser.parse_args() 24 | 25 | for ent in enum_utmp(): 26 | if ent["type"] == UtType.USER_PROCESS: 27 | if re.match(r"^mosh \[\d+\]$", ent["host"]): 28 | if args.dry_run or not args.quiet: 29 | print("detaching %(line)s (%(host)s)" % ent) 30 | if not args.dry_run: 31 | hup(ent["line"]) 32 | -------------------------------------------------------------------------------- /bin/mtime: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # mtime -- list modification time of all given files 3 | 4 | sub usage { 5 | print "Usage: mtime [-q] \n"; 6 | } 7 | 8 | if (!@ARGV) { 9 | warn "error: missing filenames\n"; 10 | usage(); 11 | exit 2; 12 | } 13 | elsif ($ARGV[0] eq "--help") { 14 | usage(); 15 | exit 0; 16 | } 17 | elsif ($ARGV[0] eq "-q") { 18 | shift @ARGV; 19 | print for map {((stat $_)[9] // "?\t"), "\n"} @ARGV; 20 | } 21 | else { 22 | print for map {((stat $_)[9] // "?\t"), "\t", $_, "\n"} @ARGV; 23 | } 24 | -------------------------------------------------------------------------------- /bin/nm-list-wifi: -------------------------------------------------------------------------------- 1 | nm-wifi-list -------------------------------------------------------------------------------- /bin/nm-wifi-list: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # nm-wifi-list -- list Wi-Fi networks through NetworkManager 3 | # 4 | # A simple wrapper that just reorders the columns to fit on my screens. 5 | 6 | if [[ -t 1 ]]; then 7 | colors=yes 8 | else 9 | colors=auto 10 | fi 11 | 12 | rescan=no 13 | 14 | while getopts "cr" OPT; do 15 | case $OPT in 16 | c) colors=yes;; 17 | r) rescan=yes;; 18 | *) exit 2;; 19 | esac 20 | done; shift $((OPTIND-1)) 21 | 22 | fields="in-use,bars,ssid,bssid,chan,rate,security,mode" 23 | 24 | nmcli -f $fields -c $colors dev wifi list --rescan $rescan | cat 25 | -------------------------------------------------------------------------------- /bin/nolid: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # nolid - disable suspend and lid-close handling while a command runs 3 | 4 | . lib.bash || exit 5 | 6 | hold="${XDG_RUNTIME_DIR?}/nolid.hold" 7 | 8 | usage() { 9 | echo "Usage: $progname -h|-r|" 10 | echo 11 | echo_opt "-h" "hold (fork into background instead of running a command)" 12 | echo_opt "-r" "release existing hold" 13 | echo_opt "-u" "unhold (alias for -r)" 14 | } 15 | 16 | name="nolid" 17 | if [[ -t 0 ]]; then 18 | tty=$(tty) 19 | name="$name on ${tty#/dev/}" 20 | fi 21 | 22 | while getopts :hru OPT; do 23 | case $OPT in 24 | h) 25 | debug "creating lockfile \"$hold\"" 26 | touch "$hold" 27 | spawn -dc nolid inotifywait -qqe delete_self "$hold" & 28 | echo "Held." 29 | exit;; 30 | r|u) 31 | debug "deleting lockfile \"$hold\"" 32 | rm -f "$hold" 33 | echo "Released." 34 | exit;; 35 | *) lib:die_getopts;; 36 | esac 37 | done; shift $((OPTIND-1)) 38 | 39 | (( $# )) || set -- ac-wait 40 | 41 | if [[ -t 0 ]]; then 42 | settitle "nolid: $1" 43 | fi 44 | 45 | systemd-inhibit --who="$name" \ 46 | --what="sleep:handle-lid-switch" \ 47 | --why="Manually inhibited" \ 48 | gnome-inhibit --always \ 49 | --who="$name" \ 50 | --what="suspend" \ 51 | --why="Manually inhibited" \ 52 | env \ 53 | LVL="$_lvl" \ 54 | _NOLID="1" \ 55 | "$@" 56 | -------------------------------------------------------------------------------- /bin/nosymlinks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # nosymlinks -- make all symlinks appear as regular files 3 | # 4 | # Used as wrapper for sftp-server as many Android SFTP clients do not support symlinks correctly. 5 | 6 | objdir="${0%/*}/../obj/host.$HOSTNAME" 7 | lib="$objdir/unsymlink.so" 8 | 9 | if [ ! -f "$lib" ]; then 10 | echo "$0: missing '$lib'" >&2 11 | fi 12 | 13 | export LD_PRELOAD="$objdir/unsymlink.so${LD_PRELOAD+:}$LD_PRELOAD" 14 | 15 | exec "$@" 16 | -------------------------------------------------------------------------------- /bin/outdent: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # outdent -- strip leading and trailing whitespace 3 | sed 's/^\s\+//; s/\s\+$//' 4 | -------------------------------------------------------------------------------- /bin/paccat: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # paccat - cat a file from a pacman package 3 | 4 | . lib.bash || exit 5 | 6 | package=$1 7 | file=$2 8 | 9 | if [[ $file != /* ]]; then 10 | if [[ $PWD/ == /home/* ]]; then 11 | file=/$file 12 | fi 13 | file=$(readlink -m "$file") 14 | fi 15 | 16 | url=$(pacman -Sddp "$package") 17 | pkg=$(basename "$url") 18 | pkg=/var/cache/pacman/pkg/$pkg 19 | 20 | if [[ ! -s $pkg ]]; then 21 | sudo pacman -Sddw --noconfirm --quiet "$package" >&2 22 | fi 23 | 24 | if [[ ! -s $pkg ]]; then 25 | die "could not download '${pkg##*/}'" 26 | fi 27 | 28 | bsdtar xfO "$pkg" "${file#/}" 29 | -------------------------------------------------------------------------------- /bin/pcf2otb.pe: -------------------------------------------------------------------------------- 1 | #!/usr/bin/fontforge 2 | # 3 | # Combine .pcf bitmap fonts into a single OpenType container, due to Pango 1.44 4 | # no longer having support for those formats. 5 | if ($argc == 1) 6 | Error("usage: opentype-bitmap.pe size1.pcf [size2.pcf ...]") 7 | endif 8 | New() 9 | i = 1 10 | while (i < $argc) 11 | Import($argv[i]) 12 | i++ 13 | endloop 14 | Generate($fullname + ".otb", "otb") 15 | Close() 16 | -------------------------------------------------------------------------------- /bin/pfb2otf.pe: -------------------------------------------------------------------------------- 1 | #!/usr/bin/fontforge 2 | # 3 | # Transform .pfa/.pfb Type-1 fonts to OpenType container, due to Pango 1.44 no 4 | # longer having support for those formats. 5 | # 6 | # Based on https://fontforge.github.io/scripting-tutorial.html 7 | if ($argc < 2) 8 | Error("usage: pfb2otf.pe ") 9 | endif 10 | i = 1 11 | while (i < $argc) 12 | Print("* " + $argv[i]) 13 | Open($argv[i]) 14 | Print(" Font name = " + $fontname) 15 | Print(" Family name = " + $familyname) 16 | Print(" Full name = " + $fullname) 17 | # Possible workaround for Windows messing up font grouping: 18 | SetTTFName(0x0, 4, $familyname) 19 | SetTTFName(0x409, 4, $familyname) 20 | Generate($argv[i]:r + ".otf") 21 | i++ 22 | endloop 23 | -------------------------------------------------------------------------------- /bin/pftp: -------------------------------------------------------------------------------- 1 | /usr/bin/ftp -------------------------------------------------------------------------------- /bin/ping6: -------------------------------------------------------------------------------- 1 | /usr/bin/ping -------------------------------------------------------------------------------- /bin/prename: -------------------------------------------------------------------------------- 1 | ../thirdparty/prename -------------------------------------------------------------------------------- /bin/putenv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | pids=() 6 | envs=() 7 | args=() 8 | 9 | while getopts ":e:p:s:" OPT; do 10 | case $OPT in 11 | e) envs+=("$OPTARG");; 12 | p) pids+=("$OPTARG");; 13 | *) lib:die_getopts;; 14 | esac 15 | done 16 | 17 | if (( ! ${#envs[@]} )); then 18 | die 2 "no environment variables specified (use -e)" 19 | fi 20 | 21 | if (( ! ${#pids[@]} )); then 22 | die 2 "no processes specified (use -p)" 23 | fi 24 | 25 | for var in "${envs[@]}"; do 26 | if [[ $var != *=* ]]; then 27 | var="$var=${!var}" 28 | fi 29 | var=$(urlencode -x "$var") || exit 30 | args+=(-ex "p putenv(\"$var\")") 31 | done 32 | 33 | for pid in "${pids[@]}"; do 34 | info "hacking process $pid" 35 | do: gdb --batch "${args[@]}" -ex detach -p "$pid" 36 | done 37 | -------------------------------------------------------------------------------- /bin/recent: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # recent -- show recently modified files in the current directory 3 | 4 | . lib.bash || exit 5 | 6 | dirs=() 7 | opts=() 8 | today=1 9 | days=1 10 | 11 | for arg; do 12 | if [[ $arg =~ ^-([0-9]+)$ ]]; then 13 | days=${BASH_REMATCH[1]} 14 | elif [[ $arg == -* ]]; then 15 | die "unknown option '$arg'" 16 | elif [[ $arg =~ ^\+([0-9]+)[Mm]$ ]]; then 17 | opts+=(-size +${BASH_REMATCH[1]}M) 18 | else 19 | dirs+=("$arg") 20 | fi 21 | done 22 | 23 | if (( ! ${#dirs[@]} )); then 24 | dirs=(.) 25 | fi 26 | 27 | if (( today )); then 28 | opts+=(-daystart) 29 | opts+=(-mtime -$days) 30 | if (( days == 1 )); then 31 | echo "Files modified today:" 32 | else 33 | echo "Files modified in the last $days days:" 34 | fi 35 | fi 36 | 37 | opts+=(-printf '%h/%f \033[2m[%kk]\033[m\n') 38 | 39 | # -mtime x 40 | # match if mtime is between {x*24 hours ago} and {(x+1)*24 hours ago} 41 | # e.g. -mtime 0 42 | # match if mtime is between {0 hours ago} and {24 hours ago} 43 | # -mtime -x 44 | # match if mtime is newer than {(x+1)*24 hours ago} 45 | # e.g. -mtime -1 46 | # match if mtime is newer than {24 hours ago} 47 | 48 | for dir in "${dirs[@]}"; do 49 | xdir=$(realpath "$dir") 50 | xdir=${xdir/#"$HOME/"/"~/"} 51 | find "$dir" -xtype f "${opts[@]}" | sed 's!^\./!!' | treeify -ffr "$xdir" 52 | done 53 | -------------------------------------------------------------------------------- /bin/rechmod: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # rechmod -- adjust file modes 3 | 4 | arg_fmode=0644 5 | arg_dmode=0755 6 | 7 | while getopts "D:F:p" OPT; do 8 | case $OPT in 9 | D) arg_dmode=$OPTARG;; 10 | F) arg_fmode=$OPTARG;; 11 | p) arg_fmode=0600 arg_dmode=0700;; 12 | esac 13 | done; shift $((OPTIND-1)) 14 | 15 | find "$@" \( -name .git -prune \) -o \( -type d -exec chmod -c "$arg_dmode" {} + \) 16 | find "$@" \( -name .git -prune \) -o \( -type f -exec chmod -c "$arg_fmode" {} + \) 17 | 18 | find "$@" -type f \( -iname "*.cmd" -o -iname "*.exe" -o -iname "*.msi" \) -exec chmod -c "a+x" {} + 19 | -------------------------------------------------------------------------------- /bin/restrainedlove: -------------------------------------------------------------------------------- 1 | wrappers/restrainedlove -------------------------------------------------------------------------------- /bin/rotate-up: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [ ! -d ~/nullroute/tmp ]; then 4 | echo "error: wrong host" >&2 5 | exit 1 6 | fi 7 | 8 | cd ~ 9 | dir=nullroute/tmp/$(date +%Y) 10 | mkdir -vp "$dir" 11 | ln -svnf "$dir" ~/up 12 | -------------------------------------------------------------------------------- /bin/secondlife: -------------------------------------------------------------------------------- 1 | wrappers/secondlife -------------------------------------------------------------------------------- /bin/sendtestmail: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | usage() { 6 | echo "Usage: ${0##*/} [-t ADDR]" 7 | echo 8 | echo_opt "-t ADDR" "Recipient address (default: '$USER')" 9 | } 10 | 11 | opt_to=$USER 12 | 13 | while getopts :t OPT; do 14 | case $OPT in 15 | t) opt_to=$OPTARG;; 16 | *) lib:die_getopts;; 17 | esac 18 | done; shift $[OPTIND-1] 19 | 20 | PATH=/usr/lib:/usr/sbin:$PATH 21 | 22 | if ! have sendmail; then 23 | vdie "sendmail program not found" 24 | else 25 | vmsg "sending test mail to self" 26 | fi 27 | 28 | sendmail -i "$opt_to" <<-EOF 29 | Subject: Test from $(hostname) 30 | Date: $(date "+%a, %d %b %Y %H:%M:%S %z") 31 | To: <$opt_to> 32 | 33 | Test mail from $USER ($UID) at $(fqdn || hostname) 34 | EOF 35 | -------------------------------------------------------------------------------- /bin/signa: -------------------------------------------------------------------------------- 1 | wrappers/signa -------------------------------------------------------------------------------- /bin/ssh-pkcs11: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # ssh-pkcs11 -- Wrapper which allows directly using PKCS#11 modules with tools 3 | # that rely on ssh-agent (such as `ssh-keygen -Y sign`). 4 | # 5 | # Note: ssh-keygen supports -D and -I options when signing certificates using a 6 | # CA key, but oddly not when signing data via -Y. 7 | 8 | dirs=(/usr/lib/pkcs11 /usr/lib) 9 | lib='p11-kit-proxy.so' 10 | do_add=0 11 | do_del=0 12 | 13 | while getopts "ad" OPT; do 14 | case $OPT in 15 | a) do_add=1;; 16 | d) do_del=1;; 17 | *) exit 2;; 18 | esac 19 | done; shift $((OPTIND-1)) 20 | 21 | if [[ ! $_SSH_PKCS11_MOD ]]; then 22 | if [[ $lib != */* ]]; then 23 | for dir in "${dirs[@]}"; do 24 | if [[ -e $dir/$lib ]]; then 25 | lib=$dir/$lib 26 | break 27 | fi 28 | done 29 | fi 30 | if [[ $lib != */* ]]; then 31 | echo "${0##*/}: Could not find PKCS#11 library '$lib'" >&2 32 | exit 1 33 | fi 34 | if (( do_add || do_del )); then 35 | if (( do_del )); then 36 | ssh-add -e "$lib" 37 | fi 38 | if (( do_add )); then 39 | ssh-add -s "$lib" 40 | fi 41 | else 42 | export _SSH_PKCS11_MOD=$lib 43 | exec ssh-agent "$0" "$@" 44 | fi 45 | else 46 | ssh-add -s "$_SSH_PKCS11_MOD" && 47 | exec "$@" || exit 48 | fi 49 | -------------------------------------------------------------------------------- /bin/sshmux: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | prefix="$HOME/.ssh/S." 6 | 7 | parse_socket() { 8 | addr="${socket#$prefix}" 9 | user="${addr%@*}" 10 | temp="${addr##*@}" 11 | host="${temp%:*}" 12 | port="${temp##*:}" 13 | } 14 | 15 | ssh_control() { 16 | ssh "$host" -l "$user" -p "$port" -S "$socket" "$@" 17 | } 18 | 19 | do_list() { 20 | printf '%-40s%s\n' "SERVER NAME" "STATUS" 21 | for socket in "$prefix"*; do 22 | test -S "$socket" || continue 23 | parse_socket 24 | if ! status=$(ssh_control -O check 2>&1); then 25 | status="${status/#Control socket connect(*): /Control socket: }" 26 | fi 27 | printf '%-40s%s\n' "$addr" "$status" 28 | done 29 | } 30 | 31 | do_kill() { 32 | for socket in "$prefix"*; do 33 | test -S "$socket" || continue 34 | parse_socket 35 | lib:echo "Stopping socket for '$addr'" 36 | ssh_control -O ${1:-stop} || rm -v "$socket" 37 | done 38 | } 39 | 40 | do_connect() { 41 | lib:echo "Starting background connection to '$*'" 42 | ssh -fNM "$@" 43 | } 44 | 45 | case $1 in 46 | -k) do_kill 'stop';; 47 | -K) do_kill 'exit';; 48 | '') do_list;; 49 | *) do_connect "$@";; 50 | esac 51 | -------------------------------------------------------------------------------- /bin/store-secret: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # store-secret -- add libsecret entries in certain known schemas 3 | 4 | . lib.bash || exit 5 | 6 | app=$1 7 | [[ $app ]] || die "usage: $progname ..." 8 | 9 | label="" 10 | attrs=() 11 | 12 | case $app in 13 | mpop|msmtp) 14 | host=$2 user=$3 15 | [[ $host && $user ]] || die "usage: $progname $app " 16 | case $app in 17 | msmtp) proto=smtp;; 18 | mpop) proto=pop3;; 19 | esac 20 | label="$app: $proto://$(urlencode "$user")@$host" 21 | attrs=( 22 | xdg:schema "de.marlam.$app.password" 23 | host "$host" 24 | service "$proto" 25 | user "$user" 26 | ) ;; 27 | rdp) 28 | # Used by ~/code/bin/rdp only. 29 | host=$2 user=$3 30 | [[ $host && $user ]] || die "usage: $progname $app " 31 | label="$app: Password for '$user' on '$host'" 32 | attrs=( 33 | xdg:schema "org.gnome.keyring.NetworkPassword" 34 | server "$host" 35 | protocol "rdp" 36 | user "$user" 37 | ) ;; 38 | *) 39 | die "unknown app '$app'" ;; 40 | esac 41 | 42 | secret-tool store --label="$label" xdg:schema "$schema" "${attrs[@]}" 43 | -------------------------------------------------------------------------------- /bin/swaks-gmail: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | host='smtp.gmail.com' 6 | user=$(getnetrc -df %u "smtp/$host") 7 | pass=$(getnetrc -df %p "smtp/$host" "$user") 8 | 9 | [[ $user && $pass ]] || die "credentials for '$host' not found in ~/.netrc" 10 | 11 | case $user in 12 | *@*) from="$user";; 13 | *) from="$user@gmail.com";; 14 | esac 15 | 16 | do: swaks \ 17 | --server "$host" \ 18 | --port 587 \ 19 | --tls \ 20 | --tls-verify \ 21 | --auth PLAIN \ 22 | --auth-user "$user" \ 23 | --auth-password "$pass" \ 24 | --from "$from" \ 25 | "$@" 26 | -------------------------------------------------------------------------------- /bin/swaks-null: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | host='mail.nullroute.lt' 6 | user='grawity' 7 | from='grawity@nullroute.lt' 8 | 9 | do: swaks \ 10 | --server "$host" \ 11 | --tls-on-connect \ 12 | --tls-verify \ 13 | --auth GSSAPI \ 14 | --auth-user "$user" \ 15 | --auth-password "foo" \ 16 | --from "$from" \ 17 | "$@" 18 | -------------------------------------------------------------------------------- /bin/swaks-uk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | host='mail.utenos-kolegija.lt' 6 | user=$(ad -f work gp "@host=$host" :login) 7 | pass=$(ad -f work gp "@host=$host" !pass) 8 | 9 | [[ $user && $pass ]] || die "credentials for '$host' not found" 10 | 11 | case $user in 12 | *@*) from="$user";; 13 | *) from="${user}@utenos-kolegija.lt";; 14 | esac 15 | 16 | do: swaks \ 17 | --server "$host" \ 18 | --port 587 \ 19 | --tls \ 20 | --tls-verify \ 21 | --auth PLAIN \ 22 | --auth-user "$user" \ 23 | --auth-password "$pass" \ 24 | --from "$from" \ 25 | "$@" 26 | -------------------------------------------------------------------------------- /bin/telnet-uri-helper: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # convert a telnet:// URI to `telnet` args 3 | 4 | . lib.bash || exit 5 | 6 | case $1 in 7 | telnet:*) 8 | uri=$1 9 | uri=${uri#'telnet:'} 10 | uri=${uri#'//'} 11 | uri=${uri%'/'} 12 | opts=() 13 | if [[ $uri == *@* ]]; then 14 | opts+=('--user' "${uri%@*}") 15 | uri=${uri##*@} 16 | else 17 | opts+=('--no-login') 18 | fi 19 | settitle "telnet: $uri" 20 | exec telnet "${opts[@]}" "$uri" 21 | ;; 22 | '') 23 | die "missing URL" 24 | ;; 25 | *) 26 | die "not a 'telnet:' URI: $1" 27 | ;; 28 | esac 29 | -------------------------------------------------------------------------------- /bin/testcidr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # testcidr -- check whether a host is within a network prefix 3 | import argparse 4 | import ipaddress 5 | import os 6 | 7 | parser = argparse.ArgumentParser() 8 | parser.add_argument("host") 9 | parser.add_argument("network") 10 | args = parser.parse_args() 11 | 12 | host = ipaddress.ip_address(args.host) 13 | net = ipaddress.ip_network(args.network) 14 | 15 | #if host.version != net.version: 16 | # exit("error: mismatching address versions") 17 | 18 | if host in net: 19 | exit(0) 20 | else: 21 | exit(1) 22 | -------------------------------------------------------------------------------- /bin/testrad: -------------------------------------------------------------------------------- 1 | ../misc/testrad -------------------------------------------------------------------------------- /bin/toml2json: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/toml2toml: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/toml2yaml: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/trackerwatch: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Monitor the progress of tracker-extract-3 3 | 4 | if [ "$1" = "-m" ]; then 5 | proc='localsearch-3' 6 | else 7 | proc='localsearch-extractor-3' 8 | fi 9 | 10 | pids=(`pidof $proc`) || { 11 | echo "$proc is not running" >&2 12 | exit 1 13 | } 14 | 15 | #if (( ${#pids[@]} > 1 )); then 16 | 17 | sudo stdbuf -oL -- strace -p ${pids[0]} -e statx |& 18 | perl -nE 'chomp; 19 | ($err) = /= -\d+ (E\w+) \(.+?\)$/; 20 | $col = $err ? 91 : 93; 21 | if(s/.*AT_FDCWD, "(.+?)", AT_STATX.*/$1/) { 22 | s/\\(\d{3})/chr oct $1/ge; 23 | s!^(.+/)([^/]+)$!\033[${col}m$2\033[m \033[2m($1$2)\033[m!; 24 | if (my $n = $seen{$&}++) { s/^/[$n] /; } 25 | say; 26 | }' 27 | -------------------------------------------------------------------------------- /bin/unar: -------------------------------------------------------------------------------- 1 | lsar -------------------------------------------------------------------------------- /bin/unhexdump: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # unhexdump -- translate `hexdump -C` output back to binary 3 | import sys 4 | import re 5 | 6 | out = open("/dev/stdout", "wb") 7 | rowlen = 16 8 | last = None 9 | same = False 10 | 11 | for line in sys.stdin: 12 | line = line.strip() 13 | if m := re.match(r"^([0-9a-f]+) ([0-9a-f ]+) \|.*\|", line): 14 | offset = int(m.group(1), 16) 15 | chunk = bytes([int(c, 16) for c in m.group(2).split()]) 16 | assert offset % rowlen == 0 17 | assert len(chunk) == rowlen 18 | if same: 19 | count = ((offset - lastoffset) // rowlen) - 1 20 | out.write(lastchunk * count) 21 | same = False 22 | out.write(chunk) 23 | lastoffset = offset 24 | lastchunk = chunk 25 | elif line == "*": 26 | same = True 27 | else: 28 | print("unrecognized line: %r" % line, file=sys.stderr) 29 | exit(1) 30 | -------------------------------------------------------------------------------- /bin/unison: -------------------------------------------------------------------------------- 1 | wrappers/unison -------------------------------------------------------------------------------- /bin/unrename: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | sub shquote { 4 | my ($str) = @_; 5 | $str =~ s/["\\`\$]/\\$&/g; 6 | return qq{"$str"}; 7 | } 8 | 9 | while (<>) { 10 | # grawity/fix-{pixiv,booru}-names 11 | if (m{^(.+/)?(.+?) => (.+)$}) { 12 | my $new = shquote("$1$3"); 13 | my $old = shquote("$1$2"); 14 | print qq{mv -vn $new $old\n}; 15 | } 16 | elsif (m{^info: renaming '(.+/)?(.+)' to '([^/]+)'$}) { 17 | my $new = shquote("$1$3"); 18 | my $old = shquote("$1$2"); 19 | print qq{mv -vn $new $old\n}; 20 | } 21 | elsif (m{^info: renaming '(.+)' to '(.+)'$}) { 22 | my $new = shquote($2); 23 | my $old = shquote($1); 24 | print qq{mv -vn $new $old\n}; 25 | } 26 | # grawity/trash 27 | elsif (m{^info: trashed '(.+)'$}) { 28 | my $old = shquote($1); 29 | print qq{trash --restore $old\n}; 30 | } 31 | # rdempty 32 | elsif (m{^info: removed: (.+)$}) { 33 | my $old = shquote($1); 34 | print qq{mkdir -p $old\n}; 35 | } 36 | # prename 37 | elsif (m{^(.+) -> (.+)$}) { 38 | my $new = shquote($2); 39 | my $old = shquote($1); 40 | print qq{mv -vn $new $old\n}; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /bin/unzlib: -------------------------------------------------------------------------------- 1 | ../misc/zlib -------------------------------------------------------------------------------- /bin/update-winbox: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | pkgver=3.22 6 | dstbin=~/.local/bin/winbox.exe 7 | 8 | case $HOSTTYPE in 9 | i686) 10 | url="https://download.mikrotik.com/winbox/${pkgver}/winbox.exe";; 11 | x86_64) 12 | url="https://download.mikrotik.com/winbox/${pkgver}/winbox64.exe";; 13 | *) 14 | die "unsupported architecture '$HOSTTYPE'";; 15 | esac 16 | 17 | wget "$url" -O "$dstbin.tmp" || 18 | die "could not download '$url'" 19 | 20 | osslsigncode verify -in "$dstbin.tmp" || 21 | die "could not verify Authenticode signature for '$dstbin'" 22 | 23 | mv -b "$dstbin.tmp" "$dstbin" 24 | chmod +x "$dstbin" 25 | info "downloaded to '$dstbin'" 26 | -------------------------------------------------------------------------------- /bin/upmove: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # upmove -- moves files from a given directory to one level above 3 | 4 | . lib.bash || exit 5 | 6 | shopt -s dotglob 7 | 8 | for dir; do 9 | debug "processing arg ${dir@Q}" 10 | if [[ ! -d "$dir" ]]; then 11 | err "item '$dir' is not a directory" 12 | continue 13 | fi 14 | if [[ "$dir" -ef . ]]; then 15 | err "item '$dir' is the current directory" 16 | continue 17 | fi 18 | dir=${dir%/} 19 | 20 | for fileA in "$dir"/*; do 21 | fileB=${fileA#"$dir/"} 22 | debug "checking file ${fileA@Q} <--> ${fileB@Q}" 23 | if [[ "$fileB" == . || "$fileB" == .. ]]; then 24 | : 25 | elif [[ -e "$fileB" ]]; then 26 | if cmp -s "$fileA" "$fileB"; then 27 | vmsg "identical files would conflict: '$fileB'" 28 | else 29 | err "file would conflict: '$fileB'" 30 | fi 31 | fi 32 | done 33 | 34 | (( !errors )) || continue 35 | 36 | find "$dir" -mindepth 1 -maxdepth 1 \ 37 | -not -name "$dir" \ 38 | -print -exec mv -t "$PWD" {} + 39 | 40 | rmdir -v "$dir" 41 | done 42 | 43 | ((!errors)) 44 | -------------------------------------------------------------------------------- /bin/uri: -------------------------------------------------------------------------------- 1 | urimap -------------------------------------------------------------------------------- /bin/vers: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | tool=$(osguess package-mgr) || exit 6 | 7 | case $tool in 8 | pacman) 9 | if ! have expac; then 10 | vdie "expac not found" 11 | fi 12 | { expac -Q '%r/%n %v' "$@" || true; 13 | expac -S '%r/%n %v' "$@" || true; } | column -t 14 | ;; 15 | *) 16 | echo "${0##*/}: unknown distribution" >&2 17 | exit 2 18 | esac 19 | -------------------------------------------------------------------------------- /bin/wg-debug: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # wg-debug -- control WireGuard debug mode 3 | 4 | if (( UID )); then 5 | echo "$0: must be run as root" >&2 6 | exit 1 7 | fi 8 | 9 | case $1 in 10 | -e|1|y|on) 11 | echo "Enabling dynamic debugging for WireGuard..." 12 | echo "module wireguard +p" > /sys/kernel/debug/dynamic_debug/control 13 | ;; 14 | -d|0|n|off) 15 | echo "Disabling dynamic debugging for WireGuard..." 16 | echo "module wireguard -p" > /sys/kernel/debug/dynamic_debug/control 17 | ;; 18 | esac 19 | 20 | current=$(awk '$2 ~ /\[wireguard\]/ {print $3}' /sys/kernel/debug/dynamic_debug/control | sort -u) 21 | 22 | case $current in 23 | '=p') 24 | echo "WireGuard debugging is currently enabled.";; 25 | '=_') 26 | echo "WireGuard debugging is currently disabled.";; 27 | *) 28 | echo "WireGuard debugging is in a mixed state.";; 29 | esac 30 | -------------------------------------------------------------------------------- /bin/whatowns: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # whatowns -- show packages owning a specific file 3 | 4 | tool=$(osguess package-mgr) || exit 5 | 6 | case $tool in 7 | dpkg) 8 | dpkg -S "$@";; 9 | pacman) 10 | pacman -Qo "$@";; 11 | rpm) 12 | rpm -q --whatprovides "$@";; 13 | pkg-freebsd) 14 | pkg which "$@";; 15 | *) 16 | echo "${0##*/}: unknown distribution" >&2 17 | exit 2 18 | esac 19 | -------------------------------------------------------------------------------- /bin/windows: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # windows -- set EFI "BootNext" variable to boot into Windows next time 3 | 4 | . lib.bash || exit 5 | 6 | usage() { 7 | echo "Usage: $progname [-b | -c]" 8 | echo "" 9 | echo_opt "-b" "reboot immediately" 10 | echo_opt "-c" "cancel (clear BootNext)" 11 | } 12 | 13 | if (( UID )); then 14 | exec sudo "$0" "$@" || die "root privileges needed" 15 | fi 16 | 17 | do_cancel=0 18 | do_reboot=0 19 | 20 | while getopts ':bcr' OPT; do 21 | case $OPT in 22 | b) do_reboot=1;; 23 | c) do_cancel=1;; 24 | r) do_reboot=1;; 25 | *) lib:die_getopts;; 26 | esac 27 | done 28 | 29 | if (( do_cancel )); then 30 | do: efibootmgr --quiet --delete-bootnext 31 | exit 32 | fi 33 | 34 | boot_id=$(efibootmgr | awk '/^Boot.* Windows Boot Manager/{print $1}') 35 | if [[ ! $boot_id ]]; then 36 | die "could not find Windows Boot Manager" 37 | fi 38 | boot_id=${boot_id#'Boot'} 39 | boot_id=${boot_id%'*'} 40 | 41 | do: efibootmgr --quiet --bootnext "$boot_id" 42 | 43 | if (( do_reboot )); then 44 | do: systemctl reboot 45 | fi 46 | -------------------------------------------------------------------------------- /bin/wpa_debuglevel: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | level=${1:-debug} 6 | 7 | case $level in 8 | on) level='debug';; 9 | off) level='info';; 10 | esac 11 | 12 | if have busctl; then 13 | sudo busctl set-property \ 14 | fi.w1.wpa_supplicant1 /fi/w1/wpa_supplicant1 \ 15 | fi.w1.wpa_supplicant1 DebugLevel s "$level" 16 | 17 | sudo busctl get-property \ 18 | fi.w1.wpa_supplicant1 /fi/w1/wpa_supplicant1 \ 19 | fi.w1.wpa_supplicant1 DebugLevel 20 | elif have gdbus; then 21 | sudo gdbus call -y \ 22 | -d fi.w1.wpa_supplicant1 \ 23 | -o /fi/w1/wpa_supplicant1 \ 24 | -m org.freedesktop.DBus.Properties.Set \ 25 | fi.w1.wpa_supplicant1 \ 26 | DebugLevel \ 27 | "<'$level'>" ; 28 | 29 | sudo gdbus call -y \ 30 | -d fi.w1.wpa_supplicant1 \ 31 | -o /fi/w1/wpa_supplicant1 \ 32 | -m org.freedesktop.DBus.Properties.Get \ 33 | fi.w1.wpa_supplicant1 \ 34 | DebugLevel ; 35 | else 36 | die "no 'busctl' nor 'gdbus' available" 37 | fi 38 | -------------------------------------------------------------------------------- /bin/wrappers/catznip: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec run-secondlife --app-name="Catznip" --icon-name="catznip" --wm-class="catznip-viewer" -- ~/.local/pkg/catznip/catznip "$@" 3 | -------------------------------------------------------------------------------- /bin/wrappers/cower: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ $1 == -u ]]; then 4 | auracle sync "${@:2}" 5 | elif [[ $1 == -i ]]; then 6 | auracle info "${@:2}" 7 | elif [[ $1 == -s ]]; then 8 | auracle search "${@:2}" 9 | else 10 | /usr/bin/cower "$@" 11 | fi 12 | -------------------------------------------------------------------------------- /bin/wrappers/dd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | progname="dd.wrap" 5 | 6 | if [[ -t 0 && -t 1 && -t 2 ]]; then 7 | set -- status=progress "$@" 8 | fi 9 | 10 | has_bs=0 11 | for arg in "$@"; do 12 | if [[ $arg == @(bs|ibs|obs)=* ]]; then 13 | has_bs=1 14 | fi 15 | done 16 | if (( !has_bs )); then 17 | vmsg "'bs=' not specified, adding default 'bs=1M'" 18 | set -- bs=1M "$@" 19 | fi 20 | 21 | exec /usr/bin/dd "$@" 22 | -------------------------------------------------------------------------------- /bin/wrappers/ffmpeg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec "/usr/bin/${0##*/}" -hide_banner "$@" 3 | -------------------------------------------------------------------------------- /bin/wrappers/firestorm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec run-secondlife --app-name="Firestorm Viewer" --icon-name="firestorm-viewer" --wm-class="firestorm-viewer" -- ~/.local/pkg/firestorm/firestorm "$@" 3 | -------------------------------------------------------------------------------- /bin/wrappers/gens: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec env \ 3 | PULSE_PROP_OVERRIDE_application.name='Gens' \ 4 | PULSE_PROP_OVERRIDE_media.role='game' \ 5 | /usr/bin/gens "$@" 6 | -------------------------------------------------------------------------------- /bin/wrappers/gio: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # wrapper to avoid the `gio` bug which doesn't wait for the application to activate 3 | # (which for some reason causes it to exit again) 4 | 5 | if [[ "$1" == "open" && -d "${2#file://}" ]]; then 6 | echo "$0: redirecting to 'gapplication launch'" >&2 7 | exec gapplication launch org.gnome.Nautilus "$2" 8 | fi 9 | 10 | exec /usr/bin/gio "$@" 11 | -------------------------------------------------------------------------------- /bin/wrappers/kokua: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec run-secondlife --app-name="Kokua" --icon-name="kokua" --wm-class="kokua-viewer" -- ~/.local/pkg/kokua/kokua "$@" 3 | -------------------------------------------------------------------------------- /bin/wrappers/pacman: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # wrapper for 'pacman' to add flock-based locking 3 | 4 | if (( UID == 0 )) && [[ ! $PACMAN_LOCK ]] && [[ ! $FAKEROOTKEY ]] && [[ $1 != "-V" ]]; then 5 | lock=/run/lock/pacman 6 | exec {fd}>"$lock" && 7 | /usr/bin/flock -xn $fd || { 8 | if [[ $DEBUG ]]; then 9 | echo "[$$:$(ps -o cmd= $PPID):$*]" 10 | fi 11 | echo -n "waiting for other instances to exit..." 12 | /usr/bin/flock -x $fd && echo "done" 13 | } >&2 14 | dblock=/var/lib/pacman/db.lck 15 | if [[ -e "$dblock" ]]; then 16 | if pid=$(pgrep -x pacman); then 17 | echo "another instance is already running" 18 | ps -f $pid 19 | exit 1 20 | fi 21 | rm -fi "$dblock" 22 | fi 23 | export PACMAN_LOCK=$fd 24 | fi 25 | 26 | exec /usr/bin/pacman "$@" 27 | -------------------------------------------------------------------------------- /bin/wrappers/restrainedlove: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec run-secondlife --app-name="Restrained Love" --icon-name="restrainedlove" --wm-class="restrainedlove" -- ~/.local/pkg/restrainedlove/secondlife "$@" 3 | -------------------------------------------------------------------------------- /bin/wrappers/secondlife: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec run-secondlife --app-name="Second Life" --icon-name="secondlife" --wm-class="secondlife-viewer" -- /opt/secondlife/secondlife "$@" 3 | -------------------------------------------------------------------------------- /bin/wrappers/signa: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | : ${WINEPREFIX:="$HOME/.wine"} 3 | wine "$WINEPREFIX/drive_c/Program Files (x86)/Signa 2010 (beta)/Signa.exe" "$@" 4 | -------------------------------------------------------------------------------- /bin/wrappers/unison: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # wrapper for 'unison' adding gnome-inhibit 3 | 4 | if [[ $1 == "-server" ]]; then 5 | exec /usr/bin/unison "$@" 6 | elif (( $# )) && [[ -t 0 ]]; then 7 | exec gnome-inhibit \ 8 | --always \ 9 | --who "Unison" \ 10 | --what "suspend" \ 11 | --why "Synchronizing" \ 12 | /usr/bin/unison "$@" 13 | else 14 | exec spawn -c \ 15 | gnome-inhibit \ 16 | --always \ 17 | --who "Unison" \ 18 | --what "suspend" \ 19 | --why "Synchronizing" \ 20 | /usr/bin/unison-gtk2 "$@" 21 | fi 22 | -------------------------------------------------------------------------------- /bin/xdg-open: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use Nullroute::Lib; 3 | 4 | my @real = ("/usr/bin/xdg-open"); 5 | 6 | for ($ENV{XDG_CURRENT_DESKTOP} // "") { 7 | if (/^GNOME$/i) { 8 | @real = ("/usr/bin/gio", "open"); 9 | } 10 | } 11 | 12 | exit(1) if !-x $real[0]; 13 | 14 | for my $orig (@ARGV) { 15 | my @xlat; 16 | unless ($orig =~ /^(git|secondlife):/) { 17 | if (open(my $proc, "-|", "uri", $orig)) { 18 | @xlat = grep {chomp || 1} <$proc>; 19 | close($proc); 20 | } 21 | } 22 | if (!@xlat) { 23 | @xlat = ($orig); 24 | } 25 | for my $uri (@xlat) { 26 | forked { exec(@real, $uri) }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /bin/xhead: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | my $max = 15; 4 | 5 | while (<>) { 6 | print if $. <= $max; 7 | } 8 | 9 | if ($. > $max) { 10 | print "\e[38;5;12m(".($. - $max)." more, ".($.)." total)\e[m\n"; 11 | } 12 | -------------------------------------------------------------------------------- /bin/xsauce: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | upload() { uguu -q "$1" 2>/dev/null; } 4 | #upload() { imgur "$1" 2>/dev/null; } 5 | upload() { command upload -q -0 -d xsauce -tt "$1"; } 6 | 7 | img="$1" && 8 | imgrgb "$img" && 9 | echo "Uploading '$img'..." && 10 | url=$(upload "$img") && 11 | url="https://saucenao.com/search.php?db=999&url=$(urlencode -a "$url")" && 12 | echo "$url" && 13 | xdg-open "$url" &>/dev/null 14 | -------------------------------------------------------------------------------- /bin/xterm-color-chooser: -------------------------------------------------------------------------------- 1 | ../misc/xterm-color-chooser -------------------------------------------------------------------------------- /bin/yaml2json: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/yaml2toml: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/yaml2yaml: -------------------------------------------------------------------------------- 1 | reserialize -------------------------------------------------------------------------------- /bin/ytdl-m4a: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | . lib.bash || exit 3 | do: youtube-dl \ 4 | --console-title \ 5 | --add-metadata \ 6 | --format "bestaudio[ext=m4a]/bestaudio" \ 7 | "$@" 8 | -------------------------------------------------------------------------------- /bin/ytdl-mkv: -------------------------------------------------------------------------------- 1 | ytdl -------------------------------------------------------------------------------- /bin/ytdl-mp3: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | . lib.bash || exit 3 | # --audio-quality is mapped to "ffmpeg -acodec libmp3lame -q:a ###" 4 | # this is for legacy use, so high quality is not as important 5 | aq=1 6 | vmsg "reminder: MP3 requires transcoding from Opus or AAC" 7 | vmsg "using libmp3lame quality level $aq" 8 | do: youtube-dl \ 9 | --console-title \ 10 | --add-metadata \ 11 | --extract-audio \ 12 | --audio-format mp3 \ 13 | --audio-quality $aq \ 14 | "$@" 15 | -------------------------------------------------------------------------------- /bin/ytdl-mp4: -------------------------------------------------------------------------------- 1 | ytdl -------------------------------------------------------------------------------- /bin/ytdl-mp4-1080p: -------------------------------------------------------------------------------- 1 | ytdl -------------------------------------------------------------------------------- /bin/ytdl-mp4-480p: -------------------------------------------------------------------------------- 1 | ytdl -------------------------------------------------------------------------------- /bin/ytdl-mp4-720p: -------------------------------------------------------------------------------- 1 | ytdl -------------------------------------------------------------------------------- /bin/zipball: -------------------------------------------------------------------------------- 1 | tarball -------------------------------------------------------------------------------- /ciscoplug: -------------------------------------------------------------------------------- 1 | shoreplug -------------------------------------------------------------------------------- /darkmode: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # darkmode -- Toggle between light/dark mode in GNOME 3 | 4 | setbacklight() { 5 | local light_mode=$1 6 | 7 | case $HOSTNAME in 8 | midnight) 9 | local hi=3043 lo=743 dev=intel_backlight;; 10 | *) 11 | return;; 12 | esac 13 | 14 | local path=/sys/class/backlight/${dev?}/brightness 15 | local current=$(< $path) 16 | if (( light_mode && current < hi )); then 17 | sudo sh -c "echo $hi > $path" 18 | elif (( !light_mode && current > lo )); then 19 | sudo sh -c "echo $lo > $path" 20 | fi 21 | } 22 | 23 | schema=org.gnome.desktop.interface 24 | key=color-scheme 25 | value="'prefer-dark'" 26 | 27 | case $(gsettings get $schema $key) in 28 | "$value") 29 | setbacklight 1 & 30 | gsettings reset $schema $key 31 | text=disabled;; 32 | *) 33 | setbacklight 0 & 34 | gsettings set $schema $key "$value" 35 | text=enabled;; 36 | esac 37 | 38 | if [ -t 1 ]; then 39 | echo "Dark Mode has been $text." 40 | else 41 | notifysend -r hotkey -e -i "dark-mode-symbolic" \ 42 | "Dark Mode" "Dark Mode has been $text." 43 | fi 44 | -------------------------------------------------------------------------------- /dist/configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | log() { echo "dist/configure: $*" >&2; } 4 | 5 | output=${1:-/dev/null} 6 | 7 | echo "/* generated */" > "$output" 8 | trap 'rm -f "$output"' INT 9 | 10 | include() { echo "#include <$1>" >> "$output"; } 11 | define() { echo "#define $*" >> "$output"; } 12 | 13 | case /$output in 14 | */config.h) 15 | if grep -qsw 'sigabbrev_np' /usr/include/string.h; then 16 | define HAVE_SIGABBREV_NP 17 | fi 18 | ;; 19 | */config-krb5.h) 20 | prefix=`krb5-config --prefix 2>/dev/null || echo /usr` 21 | vendor=`krb5-config --vendor 2>/dev/null || echo none` 22 | 23 | log "krb5 prefix: $prefix" 24 | log "krb5 vendor: $vendor" 25 | 26 | inc="$prefix/include" 27 | lib="$prefix/lib" 28 | 29 | for dir in "" {krb5,kerberosV,kerberosv5}/; do 30 | if [ -e "$inc/${dir}krb5.h" ]; then 31 | include "${dir}krb5.h" 32 | include "${dir}com_err.h" 33 | header="$inc/${dir}krb5.h" 34 | log "krb5 header: $header" 35 | break 36 | fi 37 | done 38 | 39 | if [ "$vendor" = "Massachusetts Institute of Technology" ]; then 40 | define KRB5_MIT 41 | elif [ "$vendor" = "Heimdal" ]; then 42 | define KRB5_HEIMDAL 43 | fi 44 | ;; 45 | esac 46 | -------------------------------------------------------------------------------- /dist/empty.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grawity/code/f256febd681d54b3f982e2dbb561c0fdb968d8b3/dist/empty.c -------------------------------------------------------------------------------- /dist/guess.mk: -------------------------------------------------------------------------------- 1 | CRYPT_LDLIBS := -lcrypt 2 | DL_LDLIBS := -ldl 3 | #KRB_LDLIBS := -lkrb5 -lcom_err 4 | 5 | KRB_CFLAGS = $(shell krb5-config --cflags) 6 | KRB_LDLIBS = $(shell krb5-config --libs) 7 | 8 | # allow krb5.h to include config-krb5.h 9 | KRB_CFLAGS += -I$(OBJ) 10 | 11 | ifeq ($(UNAME),Linux) 12 | OSFLAGS := -DHAVE_LINUX 13 | endif 14 | 15 | ifeq ($(UNAME),FreeBSD) 16 | OSFLAGS := -DHAVE_FREEBSD 17 | DL_LDLIBS := $(empty) 18 | endif 19 | 20 | ifeq ($(UNAME),GNU) 21 | OSFLAGS := -DHAVE_HURD 22 | endif 23 | 24 | ifeq ($(UNAME),NetBSD) 25 | OSFLAGS := -DHAVE_NETBSD 26 | endif 27 | 28 | ifeq ($(UNAME),OpenBSD) 29 | OSFLAGS := -DHAVE_OPENBSD 30 | CRYPT_LDLIBS := $(empty) 31 | DL_LDLIBS := $(empty) 32 | KRB_LDLIBS := -lkrb5 -lcom_err -lcrypto 33 | endif 34 | 35 | ifeq ($(UNAME),CYGWIN_NT-5.1) 36 | OSFLAGS := -DHAVE_CYGWIN 37 | endif 38 | 39 | ifeq ($(UNAME),SunOS) 40 | OSFLAGS := -DHAVE_SOLARIS 41 | KRB_LDLIBS := -lkrb5 42 | endif 43 | -------------------------------------------------------------------------------- /dist/update-thirdparty: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | dir="$HOME/code/thirdparty" 3 | list="$dir/SOURCE.txt" 4 | 5 | grep '^[^#]' "$list" | while read -r file url mode; do 6 | echo "$url → $file" 7 | path="$dir/$file" 8 | case $url in 9 | /afs/*) 10 | #url="https://lost-contact.mit.edu$url" ;;& 11 | scp "wind:$url" "$path" ;; 12 | http://*|https://*) 13 | curl -s -S -f -L "$url" -o "$path" ;; 14 | esac 15 | if [[ $mode ]]; then 16 | chmod "$mode" "$path" 17 | fi 18 | done 19 | -------------------------------------------------------------------------------- /egrep: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec grep -E "$@" 3 | -------------------------------------------------------------------------------- /fallback/cower: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | os=$(. /etc/os-release && echo "$ID") 6 | 7 | if [[ "$os" != "arch" ]]; then 8 | vdie "unsupported distribution '$os'" 9 | fi 10 | 11 | if (( DEBUG )); then 12 | export AURACLE_DEBUG="/dev/stderr" 13 | fi 14 | 15 | mode= 16 | 17 | while getopts ":dimsu" OPT; do 18 | case $OPT in 19 | d) mode=download;; 20 | i) mode=info;; 21 | m) mode=maintainer;; 22 | s) mode=search;; 23 | u) mode=update;; 24 | *) lib:die_getopts;; 25 | esac 26 | done; shift $((OPTIND-1)) 27 | 28 | case $mode in 29 | download) 30 | auracle clone "$@" ;; 31 | info) 32 | auracle info "$@" ;; 33 | maintainer) 34 | auracle search --searchby=maintainer "$@" ;; 35 | search) 36 | auracle search "$@" ;; 37 | update) 38 | auracle sync "$@" ;; 39 | *) 40 | vdie "operation not specified" ;; 41 | esac 42 | -------------------------------------------------------------------------------- /fallback/diff-highlight: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # wrapper that runs Git's `diff-highlight` script if it's not in bin 3 | 4 | paths=( 5 | # Arch 6 | /usr/share/git/diff-highlight 7 | # Debian 8 | /usr/share/doc/git/contrib/diff-highlight 9 | ) 10 | 11 | for dir in "${paths[@]}"; do 12 | if [[ -f $dir/diff-highlight ]]; then 13 | exec perl $dir/diff-highlight "$@" 14 | elif [[ -f $dir/DiffHighlight.pm && -f $dir/diff-highlight.perl ]]; then 15 | exec perl -I$dir -MDiffHighlight $dir/diff-highlight.perl $@ 16 | fi 17 | done 18 | 19 | echo "$0: error: could not find real diff-highlight" >&2 20 | exit 3 21 | -------------------------------------------------------------------------------- /fallback/finger: -------------------------------------------------------------------------------- 1 | ../misc/finger.py -------------------------------------------------------------------------------- /fallback/hex: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Convert input to hexadecimal. 3 | import argparse 4 | import sys 5 | 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument("-a", metavar="STRING", help="input text") 8 | args = parser.parse_args() 9 | 10 | if args.a is not None: 11 | sys.stdout.write(args.a.encode().hex()) 12 | 13 | else: 14 | while hasattr(sys.stdin, "encoding"): 15 | sys.stdin = sys.stdin.detach() 16 | 17 | while buf := sys.stdin.read(4096): 18 | sys.stdout.write(buf.hex()) 19 | -------------------------------------------------------------------------------- /fallback/hostname: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use warnings; 3 | use strict; 4 | use Sys::Hostname; 5 | 6 | sub getfqdn { 7 | my ($host) = @_; 8 | 9 | my @ret = gethostbyname($host); 10 | return $ret[0] // $host; 11 | } 12 | 13 | my $host; 14 | 15 | for my $arg ($ARGV[0]) { 16 | if (!defined $arg) { 17 | $host = hostname; 18 | } 19 | elsif ($arg eq "-s") { 20 | ($host) = split(/\./, hostname); 21 | } 22 | elsif ($arg eq "-f") { 23 | $host = getfqdn(hostname); 24 | } 25 | } 26 | 27 | print "$host\n"; 28 | -------------------------------------------------------------------------------- /fallback/strftime: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use warnings; 3 | use strict; 4 | use POSIX; 5 | use Nullroute::Lib qw(_usage _die); 6 | 7 | if (!@ARGV) { 8 | _usage(" [timestamp]"); 9 | _die("missing output format"); 10 | } 11 | 12 | my $format = shift @ARGV; 13 | 14 | push @ARGV, time if !@ARGV; 15 | 16 | print strftime($format, localtime($_))."\n" for @ARGV; 17 | -------------------------------------------------------------------------------- /fallback/telinit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | case $1 in 4 | "") echo "$0: missing argument" >&2; exit 1;; 5 | q) systemctl daemon-reload;; 6 | u) systemctl daemon-reexec;; 7 | *) echo "$0: unknown argument '$1'" >&2; exit 1;; 8 | esac 9 | -------------------------------------------------------------------------------- /fallback/unhex: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Un-convert input from hexadecimal. 3 | import argparse 4 | import io 5 | import re 6 | import sys 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument("-a", metavar="STRING", help="input text") 10 | args = parser.parse_args() 11 | 12 | if args.a is not None: 13 | input = io.StringIO(args.a) 14 | else: 15 | input = sys.stdin 16 | 17 | while hasattr(sys.stdout, "encoding"): 18 | sys.stdout = sys.stdout.detach() 19 | 20 | carry = "" 21 | while buf := input.read(4096): 22 | # "0x" stripping ought to only be applied to 1st line, but it's fine 23 | buf = re.sub(r"^0x", "", buf) 24 | buf = re.sub(r"\s+", "", buf) 25 | #buf = re.sub(r"[^0-9A-Fa-f]", "", buf) 26 | # After stripping whitespace, we might end up with an odd number of nibbles 27 | buf = carry + buf 28 | if len(buf) % 2: 29 | carry = buf[-1] 30 | buf = buf[:-1] 31 | else: 32 | carry = "" 33 | sys.stdout.write(bytes.fromhex(buf)) 34 | -------------------------------------------------------------------------------- /fallback/urlencode: -------------------------------------------------------------------------------- 1 | ../bin/urlencode.pl -------------------------------------------------------------------------------- /fallback/zlib: -------------------------------------------------------------------------------- 1 | ../misc/zlib -------------------------------------------------------------------------------- /fgrep: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec grep -F "$@" 3 | -------------------------------------------------------------------------------- /gclip: -------------------------------------------------------------------------------- 1 | pclip -------------------------------------------------------------------------------- /htelnet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env expect 2 | # htelnet -- telnet to a host that wants ^H for Backspace 3 | 4 | # Let `telnet` understand ^H at its own telnet> prompt 5 | set stty_init "erase ^H" 6 | 7 | spawn -noecho /usr/bin/telnet {*}$argv 8 | 9 | interact { 10 | # Translate Backspace to ^H 11 | "\177" { send "\010" } 12 | 13 | # Exit on Ctrl-] Ctrl-] 14 | "\035\035" { send_user "\033\[1m\033\[m\n"; exit } 15 | "\035q" { send_user "\033\[1m\033\[m\n"; exit } 16 | 17 | # Send Break on Ctrl-] Ctrl-B 18 | "\035\002" { send "\035"; expect "telnet>"; send "send brk\n" } 19 | "\035b" { send "\035"; expect "telnet>"; send "send brk\n" } 20 | 21 | # Use Ctrl-Backslash to escape itself and Ctrl-] 22 | "\034\034" { send "\034" } 23 | "\034\035" { send "\035" } 24 | } 25 | -------------------------------------------------------------------------------- /irc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # irc -- attach to my tmux session with the IRC client 3 | 4 | . lib.bash || exit 5 | 6 | usage() { 7 | echo "Usage: $progname [-f] [-m]" 8 | echo 9 | echo_opt "-f" "allow duplicate attach" 10 | echo_opt "-m" "use Mosh" 11 | } 12 | 13 | session=${XDG_SESSION_ID:-${DISPLAY:-${WAYLAND_DISPLAY:-none}}} 14 | lockfile=${XDG_RUNTIME_DIR?}/irc-$session.lock 15 | 16 | opt_mosh=0 17 | opt_force=0 18 | 19 | while getopts :fms OPT; do 20 | case $OPT in 21 | f) opt_force=1;; 22 | m) opt_mosh=1;; 23 | s) opt_mosh=0;; 24 | *) lib:die_getopts;; 25 | esac 26 | done; shift $((OPTIND-1)) 27 | 28 | . ~/.config/nullroute.lt/irc.conf || exit 29 | 30 | exec {fd}<>"$lockfile" 31 | if (( !opt_force )); then 32 | flock -xn $fd || vdie "already connected from $HOSTNAME/$session" 33 | fi 34 | 35 | if (( opt_mosh )); then 36 | export MOSH_TITLE_NOPREFIX=y 37 | mosh "${irc_host?}" -- tmux attach -t irc; r=$? 38 | else 39 | ssh -t "${irc_host?}" "tmux attach -t irc"; r=$? 40 | fi 41 | 42 | exec {fd}>&- 43 | hi &> /dev/null & 44 | exit $r 45 | -------------------------------------------------------------------------------- /kerberos/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | $(MAKE) -C .. 3 | 4 | clean: 5 | $(MAKE) -C .. clean 6 | 7 | .PHONY: all clean 8 | -------------------------------------------------------------------------------- /kerberos/k5translate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # k5translate -- Map Kerberos principal names to local account names 3 | k5userok -t -- "$@" | awk '{printf "%-40s %s\n", $1, $2}' 4 | -------------------------------------------------------------------------------- /kerberos/kc.bash: -------------------------------------------------------------------------------- 1 | kc.sh -------------------------------------------------------------------------------- /kerberos/kc.sh: -------------------------------------------------------------------------------- 1 | #!bash 2 | # kc.sh - Kerberos credential cache juggler (wrapper script) 3 | # 4 | # Must be sourced (ie. from bashrc) in order for cache switching to work. 5 | 6 | kc() { 7 | local ev; { ev=$(command kc "$@" 3>&1 >&4); } 4>&1 && eval "$ev" 8 | } 9 | -------------------------------------------------------------------------------- /kerberos/krb5.h: -------------------------------------------------------------------------------- 1 | #if defined(HAVE_KRB5_H) 2 | # include 3 | #elif defined(HAVE_FREEBSD) 4 | # include 5 | # include 6 | #elif defined(HAVE_NETBSD) 7 | # include 8 | # include 9 | #elif defined(HAVE_OPENBSD) 10 | # include 11 | # include 12 | #elif defined(HAVE_SOLARIS) 13 | # include 14 | # include 15 | #else 16 | # include 17 | #endif 18 | 19 | #if defined(KRB5_KRB5_H_INCLUDED) 20 | # define KRB5_MIT 21 | # define HAVE_KRB5_COLLECTIONS 22 | # define HAVE_KRB5_CONFIG_PRINCIPALS 23 | #elif defined(_KRB5_H) 24 | # define KRB5_MIT 25 | # define KRB5_MIT_SOLARIS 26 | #elif defined(__KRB5_H__) 27 | # define KRB5_HEIMDAL 28 | #endif 29 | 30 | #include "config-krb5.h" 31 | -------------------------------------------------------------------------------- /kerberos/lskeytab: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use List::MoreUtils 'uniq'; 3 | use feature 'say'; 4 | 5 | my %hosts; 6 | my %services; 7 | my %kvnos; 8 | 9 | my @cmd = @ARGV ? ("klist", "-k", shift(@ARGV)) 10 | : ("klist", "-k"); 11 | 12 | if (open(my $fh, "-|", @cmd)) { 13 | my $skip = 3; 14 | while (<$fh>) { 15 | next if $skip and $skip--; 16 | if (/^\s*(\d+)\s+(\S+)@(\S+)$/) { 17 | my ($kvno, $princ, $realm) = ($1, $2, $3); 18 | my ($svc, $host) = split(m|/|, $princ, 2); 19 | push @{$hosts{$host}}, $svc; 20 | push @{$services{$svc}}, $host; 21 | push @{$kvnos{$princ}}, $kvno; 22 | } 23 | } 24 | close($fh); 25 | } 26 | 27 | for my $host (sort keys %hosts) { 28 | say "host $host:"; 29 | say " ", join(" ", map { 30 | $_."(".join(",", uniq sort @{$kvnos{"$_/$host"}}).")" 31 | } uniq sort {lc $a cmp lc $b} @{$hosts{$host}}); 32 | } 33 | -------------------------------------------------------------------------------- /kf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # kf -- forward Kerberos TGT to remote hosts 3 | import argparse 4 | import gssapi 5 | import os 6 | import subprocess 7 | import sys 8 | 9 | def is_local(host): 10 | return host.lower() == os.uname().nodename.lower() 11 | 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument("host", nargs="+") 14 | args = parser.parse_args() 15 | 16 | princ = gssapi.Credentials(usage="initiate").name 17 | realm = str(princ).rpartition("@")[-1] 18 | 19 | # SSH will do the GSSAPI dance for delegating a ticket -- just need to copy it 20 | # from the per-connection cache to the default cache. 21 | 22 | print(f"Forwarding tickets for {princ}...") 23 | cmd = f"kvno -q --out-cache FILE:/tmp/krb5cc_$(id -u) krbtgt/{realm}" 24 | errors = 0 25 | procs = [] 26 | 27 | for host in args.host: 28 | if is_local(host): 29 | print(f"{host} skipped (local)") 30 | continue 31 | proc = subprocess.Popen(["ssh", "-S", "none", "-K", host, cmd]) 32 | procs.append((host, proc)) 33 | 34 | for host, proc in procs: 35 | r = proc.wait() 36 | if r == 0: 37 | print(f"{host} OK") 38 | else: 39 | print(f"{host} = {r!r}", file=sys.stderr) 40 | errors = 1 41 | 42 | exit(errors) 43 | -------------------------------------------------------------------------------- /lastdown: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # lastdown -- show the last time the system was turned off 3 | 4 | . lib.bash || exit 5 | 6 | usage() { 7 | echo "Usage: $progname [-q]" 8 | echo "" 9 | echo_opt "-q" "print only the timestamp" 10 | } 11 | 12 | opt_quiet=0 13 | 14 | while getopts :q OPT; do 15 | case $OPT in 16 | q) opt_quiet=1;; 17 | *) lib:die_getopts;; 18 | esac 19 | done; shift $[OPTIND-1] 20 | 21 | if (( $# )); then 22 | vdie "excess arguments" 23 | fi 24 | 25 | text="went to sleep" 26 | x=$(journalctl -b -o json -n 1 MESSAGE_ID=6bbd95ee977941e497c48be27c254128) 27 | if [[ ! $x ]]; then 28 | text="was shut down" 29 | x=$(journalctl -b -1 -o json -n 1) 30 | fi 31 | 32 | if [[ $x ]]; then 33 | ts=$(jq -r .__REALTIME_TIMESTAMP <<< "$x") 34 | ts=$[ts/1000000] 35 | if (( !opt_quiet )); then 36 | abstime=$(date -d @$ts +"%F %T") 37 | reltime=$(interval $[`date +%s` - ts]) 38 | echo "System $text $reltime ago ($abstime)" 39 | else 40 | echo "$ts" 41 | fi 42 | else 43 | xxxxx 44 | fi 45 | -------------------------------------------------------------------------------- /lastwake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # lastwake -- show time since system resumed from sleep 3 | # 4 | # Similar to `uptime` but returns only the duration of the current session. 5 | 6 | . lib.bash || exit 7 | 8 | usage() { 9 | echo "Usage: $progname [-q]" 10 | echo "" 11 | echo_opt "-q" "print only the timestamp" 12 | } 13 | 14 | opt_quiet=0 15 | 16 | while getopts :q OPT; do 17 | case $OPT in 18 | q) opt_quiet=1;; 19 | *) lib:die_getopts;; 20 | esac 21 | done; shift $[OPTIND-1] 22 | 23 | if (( $# )); then 24 | vdie "excess arguments" 25 | fi 26 | 27 | x=$(journalctl -b -o json -n 1 MESSAGE_ID=8811e6df2a8e40f58a94cea26f8ebf14) 28 | 29 | if [[ $x ]]; then 30 | ts=$(jq -r .__REALTIME_TIMESTAMP <<< "$x") 31 | ts=$[ts/1000000] 32 | if (( !opt_quiet )); then 33 | abstime=$(date -d @$ts +%T) 34 | reltime=$(interval $[`date +%s` - ts]) 35 | echo "System resumed from sleep $reltime ago ($abstime)" 36 | else 37 | echo "$ts" 38 | fi 39 | else 40 | if (( !opt_quiet )); then 41 | echo "System did not sleep since last boot." 42 | fi 43 | exit 1 44 | fi 45 | -------------------------------------------------------------------------------- /lcpkg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # lcpkg -- list the contents of a system package, in color 3 | 4 | case ${0##*/} in 5 | llpkg) 6 | opts="-lh";; 7 | *) 8 | opts="";; 9 | esac 10 | 11 | for pkg; do 12 | lspkg "$pkg" | xargs -d '\n' ls $opts -d --color=always 2>&1 | ${PAGER:-less} 13 | done 14 | -------------------------------------------------------------------------------- /lda: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # lda -- call Dovecot's local delivery agent to import messages into IMAP INBOX 3 | 4 | mailhost=star 5 | 6 | if [ -t 0 ]; then 7 | echo "${0##*/}: expecting a mail message on stdin" >&2 8 | exit 2 9 | fi 10 | 11 | if [ "$(hostname)" != $mailhost ]; then 12 | echo "${0##*/}: delivering through $mailhost" >&2 13 | fi 14 | 15 | ssh $mailhost /usr/lib/dovecot/dovecot-lda -e -m "${1:-INBOX}" 16 | -------------------------------------------------------------------------------- /less: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | case $TERM in xterm*|tmux*) 4 | # Display emphasis in manual pages as italics instead of underline. 5 | # This only works with the "classic" output mode i.e. GROFF_NO_SGR 6 | # (grotty -c). Note that Debian patches groff to use classic mode for 7 | # manual pages by default (with GROFF_SGR to re-enable modern mode). 8 | export LESS_TERMCAP_us=$'\e[3m' 9 | export LESS_TERMCAP_ue=$'\e[23m' 10 | esac 11 | 12 | exec /usr/bin/less "$@" 13 | -------------------------------------------------------------------------------- /lib/cidr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | class Cidr 5 | { 6 | static bool IsIPAddressInNetwork(string host, string net) 7 | { 8 | string[] tmp = net.Split("/", 2); 9 | IPAddress haddr = IPAddress.Parse(host); 10 | IPAddress naddr = IPAddress.Parse(tmp[0]); 11 | int plen = Int32.Parse(tmp[1]); 12 | 13 | if (haddr.AddressFamily != naddr.AddressFamily) 14 | return false; 15 | 16 | byte[] hbyte = haddr.GetAddressBytes(); 17 | byte[] nbyte = naddr.GetAddressBytes(); 18 | int bad = 0; 19 | 20 | if (hbyte.Length != nbyte.Length) 21 | return false; 22 | 23 | if (plen < 0 || plen > hbyte.Length*8) 24 | return false; 25 | 26 | for (int i = 0; i < hbyte.Length && plen > 0; i++) { 27 | int bits = Math.Min(plen, 8); 28 | int bmask = (0xFF00 >> bits) & 0xFF; 29 | bad |= (hbyte[i] ^ nbyte[i]) & bmask; 30 | plen -= 8; 31 | } 32 | 33 | return (bad == 0); 34 | } 35 | 36 | static void Main(string[] args) 37 | { 38 | string host = args[0]; 39 | string net = args[1]; 40 | 41 | if (IsIPAddressInNetwork(host, net)) { 42 | Console.WriteLine("yes, "+host+" is in network "+net); 43 | } else { 44 | Console.WriteLine("no, "+host+" is not in network "+net); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/cidr.ps1: -------------------------------------------------------------------------------- 1 | Function Test-IpInNetwork { 2 | Param([string]$Address, [string]$Network) 3 | $tmp = $Network.Split("/", 2) 4 | $haddr = [System.Net.IPAddress]::Parse($Address) 5 | $naddr = [System.Net.IPAddress]::Parse($tmp[0]) 6 | $plen = [int]$tmp[1] 7 | if ($haddr.AddressFamily -ne $naddr.AddressFamily) { 8 | return $false 9 | } 10 | $hbyte = $haddr.GetAddressBytes() 11 | $nbyte = $naddr.GetAddressBytes() 12 | $bad = 0 13 | if ($hbyte.Length -ne $nbyte.Length -Or $plen -notin 0..($hbyte.Length*8)) { 14 | return $false 15 | } 16 | for ($i = 0; $i -le $hbyte.Length -And $plen -gt 0; $i++) { 17 | $bits = [math]::Min($plen, 8) 18 | $bmask = (0xFF00 -shr $bits) -band 0xFF 19 | $bad = $bad -bor (($hbyte[$i] -bxor $nbyte[$i]) -band $bmask) 20 | $plen -= 8 21 | } 22 | return ($bad -eq 0) 23 | } 24 | 25 | Test-IpInNetwork -Address 10.45.197.56 -Network 10.45.0.0/16 26 | Test-IpInNetwork -Address 10.45.197.56 -Network 10.45.0.0/17 27 | Test-IpInNetwork -Address 10.3.4.4 -Network fe80::/64 28 | Test-IpInNetwork -Address 2001:778:e27f::1 -Network fe80::/64 29 | Test-IpInNetwork -Address 2001:778:e27f::1 -Network 2001:778::/48 30 | Test-IpInNetwork -Address 2001:778:e27f::1 -Network 2001:778:e27f::/48 31 | -------------------------------------------------------------------------------- /lib/kc.bash: -------------------------------------------------------------------------------- 1 | ../kerberos/kc.bash -------------------------------------------------------------------------------- /lib/perl5/Nullroute/Str.pm: -------------------------------------------------------------------------------- 1 | package Nullroute::Str; 2 | use parent "Exporter"; 3 | 4 | @EXPORT_OK = qw( 5 | expand_ranges 6 | ); 7 | 8 | # expands numeric ranges like "1,5,9-12" 9 | 10 | sub expand_ranges { 11 | my ($s) = @_; 12 | 13 | map { 14 | if (/^(\d+)-(\d+)$/) { 15 | int($1) .. int($2) 16 | } elsif (/^(\d+)$/) { 17 | int($1) 18 | } else { 19 | warn "invalid range item '$_'"; 20 | () 21 | } 22 | } split(/,/, $s); 23 | } 24 | -------------------------------------------------------------------------------- /lib/perl5/Nullroute/_Lib.pl: -------------------------------------------------------------------------------- 1 | # boilerplate for scripts that only need the logging functions of Lib.pm 2 | 3 | BEGIN { 4 | if (eval {require Nullroute::Lib}) { 5 | Nullroute::Lib->import(qw(_debug _warn _err _die)); 6 | } else { 7 | our ($arg0, $warnings, $errors); 8 | $::arg0 = (split m!/!, $0)[-1]; 9 | $::debug = !!$ENV{DEBUG}; 10 | sub _debug { warn "debug: @_\n" if $::debug; } 11 | sub _warn { warn "warning: @_\n"; ++$::warnings; } 12 | sub _err { warn "error: @_\n"; ! ++$::errors; } 13 | sub _die { _err(@_); exit 1; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/php/syslog.php: -------------------------------------------------------------------------------- 1 | host = $host; 15 | $this->sock = $sock ? $sock : stream_socket_client($host); 16 | 17 | $this->facility = LOG_AUTHPRIV; 18 | $this->hostname = $_SERVER["SERVER_NAME"]; 19 | } 20 | 21 | public function send($priority, $msg, $id=null) { 22 | if (!$this->sock) 23 | return; 24 | 25 | $priority |= $this->facility; 26 | $version = "1"; 27 | $structured = null; 28 | 29 | $buf = "<" . $priority . ">" . $version; 30 | $buf .= " " . date(DATE_RFC3339); 31 | $buf .= " " . self::strnul($this->hostname); 32 | $buf .= " " . self::strnul($this->processname); 33 | $buf .= " " . self::strnul($this->processid); 34 | $buf .= " " . self::strnul($id); 35 | $buf .= " " . self::strnul($structured); 36 | $buf .= " " . "\xEF\xBB\xBF".$msg; 37 | 38 | fwrite($this->sock, $buf); 39 | fflush($this->sock); 40 | } 41 | 42 | static function strnul($str) { 43 | return strlen($str) ? $str : "-"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/php/time-age.php: -------------------------------------------------------------------------------- 1 | 10 | """ 11 | offset = int(hmac_sha1[-1], 16) 12 | binary = int(hmac_sha1[(offset * 2):((offset * 2) + 8)], 16) & 0x7fffffff 13 | return str(binary) 14 | 15 | def HOTP(K, C, digits=6): 16 | C_bytes = struct.pack(b"!Q", C) 17 | hmac_sha1 = hmac.new(key=K, msg=C_bytes, digestmod=sha1).hexdigest() 18 | return Truncate(hmac_sha1)[-digits:] 19 | 20 | def TOTP(K, digits=6, when=None, window=30): 21 | C = int((when or time.time()) / window) 22 | return HOTP(K, C, digits=digits) 23 | 24 | def SteamTOTP(K, digits=5, when=None): 25 | chars = "23456789BCDFGHJKMNPQRTVWXY" 26 | otp = int(TOTP(K, digits=0, when=when)) 27 | out = "" 28 | for c in range(digits): 29 | otp, i = divmod(otp, len(chars)) 30 | out += chars[i] 31 | return out 32 | -------------------------------------------------------------------------------- /lib/python/nullroute/ui/win32.py: -------------------------------------------------------------------------------- 1 | from ctypes import byref, POINTER, windll, WINFUNCTYPE 2 | from ctypes.wintypes import BOOL, DWORD, HANDLE 3 | 4 | # Based on: 5 | # https://github.com/ytdl-org/youtube-dl/issues/15758#issuecomment-370630896 6 | 7 | FILE_TYPE_CHAR = 0x0002 8 | FILE_TYPE_REMOTE = 0x8000 9 | 10 | STD_INPUT_HANDLE = -10 11 | STD_OUTPUT_HANDLE = -11 12 | STD_ERROR_HANDLE = -12 13 | 14 | ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200 15 | ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 16 | 17 | GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32)) 18 | GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(("GetConsoleMode", windll.kernel32)) 19 | SetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, DWORD)(("SetConsoleMode", windll.kernel32)) 20 | 21 | def enable_vt(): 22 | h = GetStdHandle(STD_OUTPUT_HANDLE) 23 | if h is None or h == HANDLE(-1): 24 | return False 25 | mode = DWORD() 26 | if not GetConsoleMode(h, byref(mode)): 27 | return False 28 | if SetConsoleMode(h, mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING): 29 | return True 30 | return False 31 | -------------------------------------------------------------------------------- /lib/python/nullroute/urlcache.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import json 3 | import os 4 | import time 5 | import xdg.BaseDirectory 6 | 7 | class JsonCache(object): 8 | cache_dir = xdg.BaseDirectory.save_cache_path("nullroute.eu.org/url") 9 | 10 | def __init__(self, expiry=0): 11 | self.expiry = expiry or 86400 12 | 13 | def get_path(self, name): 14 | name = hashlib.sha1(name.encode("utf-8")).hexdigest() 15 | return os.path.join(self.cache_dir, "%s.json" % name) 16 | 17 | def load(self, name): 18 | path = self.get_path(name) 19 | try: 20 | with open(path, "r") as fh: 21 | package = json.load(fh) 22 | if package.get("expire", 0) >= time.time(): 23 | return package["data"] 24 | else: 25 | os.unlink(path) 26 | except FileNotFoundError: 27 | pass 28 | return None 29 | 30 | def save(self, name, data, expiry=0): 31 | expiry = expiry or self.expiry 32 | path = self.get_path(name) 33 | package = { 34 | "source": name, 35 | "obtain": time.time(), 36 | "expire": time.time() + expiry, 37 | "data": data, 38 | } 39 | with open(path, "w") as fh: 40 | json.dump(package, fh) 41 | 42 | def drop(self): 43 | os.unlink(self.get_path()) 44 | -------------------------------------------------------------------------------- /lib/python/nullroute/windows/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grawity/code/f256febd681d54b3f982e2dbb561c0fdb968d8b3/lib/python/nullroute/windows/__init__.py -------------------------------------------------------------------------------- /lib/testlib.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | --() { echo; echo "-- $*"; echo; } 4 | 5 | . lib.bash 6 | 7 | messages() { 8 | (die "fatal message") 9 | err "error message" 10 | warn "warning message" 11 | log2 "log2 message" 12 | lib:log "log message" 13 | info "info message" 14 | msg "msg message" 15 | debug "debug message" 16 | lib:trace "trace message" 17 | true 18 | } 19 | 20 | -- 'messages (normal)' -- 21 | 22 | DEBUG='' messages 23 | 24 | -- 'messages ($DEBUG)' -- 25 | 26 | DEBUG=1 messages 27 | 28 | -- 'backtraces ($DEBUG=2)' -- 29 | 30 | foo() { bar; } 31 | bar() { baz; } 32 | baz() { warn "something failed"; } 33 | 34 | DEBUG=2 foo 35 | 36 | true 37 | -------------------------------------------------------------------------------- /lib/testlib.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use Nullroute::Lib; 3 | 4 | sub test_sep { 5 | print "\n-- @_ --\n\n"; 6 | } 7 | 8 | sub child (&) { 9 | if (my $p = fork) { 10 | waitpid($p, 0); 11 | } else { 12 | exit shift->(); 13 | } 14 | } 15 | 16 | sub foo { bar(); } 17 | sub bar { baz(); } 18 | sub baz { test_log(); } 19 | sub test_log { 20 | _debug("debug message"); 21 | _info("info message"); 22 | _log("log message"); 23 | _log2("log2 message"); 24 | _notice("notice message"); 25 | _warn("warning message"); 26 | _err("error message"); 27 | _die("fatal message"); 28 | } 29 | 30 | for (@ARGV) { 31 | if ($_ eq "debug") { 32 | Nullroute::Lib::__extdebug_toggle(1); 33 | } 34 | elsif ($_ eq "nodebug") { 35 | Nullroute::Lib::__extdebug_toggle(0); 36 | } 37 | } 38 | 39 | exit if @ARGV; 40 | 41 | test_sep("messages (normal)"); 42 | 43 | $::debug = 0; child { foo() }; 44 | 45 | test_sep("messages (debug)"); 46 | 47 | $::debug = 1; child { foo() }; 48 | 49 | test_sep("messages (debug 2)"); 50 | 51 | $::debug = 2; child { foo() }; 52 | -------------------------------------------------------------------------------- /lib/testlib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | from nullroute.core import Core 4 | import sys 5 | 6 | def forked(func): 7 | if os.fork(): 8 | os.wait() 9 | else: 10 | func() 11 | sys.exit() 12 | 13 | def foo(): bar() 14 | 15 | def bar(): baz() 16 | 17 | def baz(): test_log() 18 | 19 | def test_log(): 20 | Core.trace("trace message") 21 | Core.debug("debug message") 22 | Core.info("info message") 23 | Core.notice("notice message") 24 | Core.warn("warning message") 25 | Core.err("error message") 26 | Core.die("fatal message", status=0) 27 | 28 | print("\n-- messages --\n") 29 | 30 | forked(foo) 31 | 32 | print("\n-- messages ($DEBUG) --\n") 33 | 34 | Core.raise_log_level(Core.LOG_TRACE) 35 | 36 | forked(foo) 37 | -------------------------------------------------------------------------------- /llpkg: -------------------------------------------------------------------------------- 1 | lcpkg -------------------------------------------------------------------------------- /loc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exclude='/\.old/|/\.local/share/Trash/' 4 | 5 | locate -Abi "$@" | egrep -v "$exclude" 6 | 7 | case $(hostname) in frost) 8 | # frost is low on disk capacity, so a large part of ~/Dropbox has been 9 | # mounted from /n/ember. 10 | on -H ember locate -Abi "$@" | egrep -v "$exclude" | sed "s,^,/net/ember," 11 | esac 12 | -------------------------------------------------------------------------------- /lshung: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # lshung -- list processes in uninterruptible sleep 3 | 4 | if (( UID != 0 )); then 5 | echo "${0##*/}: not enough privileges to see wchan information" >&2 6 | fi 7 | 8 | ps -e -o pid,ppid,stat,wchan:22,command | awk 'NR == 1 || $3 ~ /^[DZ]/' 9 | -------------------------------------------------------------------------------- /lsort: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # lsort -- sort text by line length 3 | 4 | print for sort {length $a <=> length $b} <>; 5 | -------------------------------------------------------------------------------- /lspkg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # lspkg -- list the contents of a system package 3 | 4 | tool=$(osguess package-mgr) || exit 5 | 6 | case $tool in 7 | dpkg) 8 | dpkg -L -- "$@";; 9 | pacman) 10 | pacman -Qql -- "$@";; 11 | rpm) 12 | rpm -ql -- "$@";; 13 | pkg-freebsd) 14 | pkg query %Fp -- "$@";; 15 | apk) 16 | apk info -Lq -- "$@" | grep .;; 17 | *) 18 | echo "${0##*/}: unknown distribution" >&2 19 | exit 2 20 | esac 21 | -------------------------------------------------------------------------------- /lspkgs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # lspkgs -- list packages 3 | 4 | tool=$(osguess package-mgr) || exit 5 | 6 | case $tool in 7 | dpkg) 8 | dpkg -l | awk '/^i/ {print $2}';; 9 | pacman) 10 | pacman -Qq;; 11 | rpm) 12 | rpm -qa --qf '%{NAME}\n';; 13 | pkg-freebsd) 14 | pkg info -q;; 15 | apk) 16 | apk info;; 17 | *) 18 | echo "${0##*/}: unknown distribution" >&2 19 | exit 2 20 | esac 21 | -------------------------------------------------------------------------------- /man: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Force using the ~/bin/less wrapper for LESS_TERMCAP overrides. 4 | if [ ! "$PAGER" ] && [ ! "$MANPAGER" ]; then 5 | export PAGER="less" 6 | fi 7 | 8 | # Disable "new" rendering mode in grotty(1) so that the LESS_TERMCAP overrides 9 | # would work. (Note: Debian already disables this by default and adds GROFF_SGR 10 | # to un-do that, so let's honor that here as well.) 11 | if [ ! "$GROFF_SGR" ]; then 12 | export GROFF_NO_SGR=1 13 | fi 14 | 15 | # Initialize to (approximately) the default 'man -r' value 16 | export MANLESS="?ltline %lt?L/%L.:byte %bB?s/%s..?pB (%pB\\%). " 17 | 18 | # Set terminal title to "manpage(section)". 19 | #case $TERM in 20 | # xterm*) 21 | # export MANLESS="${MANLESS}$(printf '\e]0;$MAN_PN\a')";; 22 | # tmux*) 23 | # export MANLESS="${MANLESS}$(printf '\ek$MAN_PN\e\\\\')";; 24 | # *) 25 | # export MANLESS="\$MAN_PN ${MANLESS}";; 26 | #esac 27 | # Unfortunately, less v591 broke the use of \e in prompt strings -- so it works 28 | # on Fujitsu but not on any of my other machines -- therefore disable it for now. 29 | export MANLESS="\$MAN_PN ${MANLESS}" 30 | 31 | exec /usr/bin/man "$@" 32 | -------------------------------------------------------------------------------- /misc/Makefile: -------------------------------------------------------------------------------- 1 | loghack-libss.so: CFLAGS := -I"$(HOME)/e2fsprogs/lib" -fPIC -shared 2 | loghack-libss.so: LDLIBS := -ldl 3 | loghack-libss.so: loghack-libss.c 4 | $(CC) $(CFLAGS) -o $@ $< $(LDLIBS) 5 | 6 | loghack-glib.so: CFLAGS += $(shell pkg-config --cflags glib-2.0) -fPIC -shared 7 | loghack-glib.so: LDLIBS += $(shell pkg-config --libs glib-2.0) 8 | loghack-glib.so: loghack-glib.c 9 | $(CC) $(CFLAGS) -o $@ $< $(LDLIBS) 10 | -------------------------------------------------------------------------------- /misc/Send-Syslog.ps1: -------------------------------------------------------------------------------- 1 | # Send-Syslog -- send a syslog message via UDP 2 | # 3 | # This currently is hardcoded to sending an ALERT-level message because I use 4 | # such messages to trigger push notifications. 5 | 6 | Param($Tag, $Text); 7 | 8 | # TODO: Look up 'syslog' via DNS 9 | $ServerIP = "10.147.1.4"; 10 | 11 | $FAC_USER = 1; 12 | $SEV_ALERT = 1; 13 | 14 | $nil = "-"; 15 | $pri = ($FAC_USER * 8) + $SEV_ALERT; 16 | $time = Get-Date -AsUTC -UFormat "%Y-%m-%dT%H:%M:%SZ"; 17 | #$time = Get-Date -AsUTC -Format "yyyy-MM-ddTHH:mm:ssZ"; 18 | $hostname = $env:COMPUTERNAME; 19 | $appname = $Tag; 20 | $procid = $nil; 21 | $msgid = $nil; 22 | $sdata = $nil; 23 | $buf = "<$pri>1 $time $hostname $appname $procid $msgid $sdata $Text"; 24 | $buf = [System.Text.Encoding]::UTF8.GetBytes($buf); 25 | 26 | $af = [System.Net.Sockets.AddressFamily]::InterNetwork 27 | $sf = [System.Net.Sockets.SocketType]::Dgram 28 | $pf = [System.Net.Sockets.ProtocolType]::UDP 29 | $sock = New-Object System.Net.Sockets.Socket $af, $sf, $pf 30 | 31 | $addr = [System.Net.IPAddress]::Parse($ServerIP) 32 | $port = 514 33 | $ep = New-Object System.Net.IPEndpoint $addr, $port 34 | $sock.Connect($ep) 35 | $res = $sock.Send($buf) 36 | -------------------------------------------------------------------------------- /misc/Send-WakeOnLan.ps1: -------------------------------------------------------------------------------- 1 | # wol -- send a Wake-on-LAN broadcast 2 | # 3 | # An experiment in pure-PowerShell socket usage. 4 | 5 | Param($MacAddress); 6 | 7 | $buf = New-Object byte[] (6*17) 8 | $mac = $MacAddress.Split(":") | % { [Convert]::ToByte($_, 16) } 9 | for ($i = 0; $i -le 16; $i++) { 10 | for ($p = 0; $p -lt 6; $p++) { 11 | $ofs = ($i * 6) + $p 12 | if ($i -eq 0) { 13 | $buf[$ofs] = 0xFF 14 | } else { 15 | $buf[$ofs] = $mac[$p] 16 | } 17 | } 18 | } 19 | 20 | $addr = [System.Net.IPAddress]::Parse("255.255.255.255") 21 | $port = 9 22 | 23 | $af = [System.Net.Sockets.AddressFamily]::InterNetwork 24 | $sf = [System.Net.Sockets.SocketType]::Dgram 25 | $pf = [System.Net.Sockets.ProtocolType]::UDP 26 | $sock = New-Object System.Net.Sockets.Socket $af, $sf, $pf 27 | #$sock.TTL = 26 28 | $ep = New-Object System.Net.IPEndpoint $addr, $port 29 | $sock.Connect($ep) 30 | $res = $sock.Send($buf) 31 | #Write-Host "{0} characters sent to: {1} " -f $res, $addr 32 | -------------------------------------------------------------------------------- /misc/VBoxHeadlessVRDE: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | vm=$1 4 | port=0 5 | 6 | _minport=43000 7 | while read -r _vm _port _; do 8 | if [[ "$_vm" == "$vm" ]]; then 9 | port=$_port 10 | elif (( _port > _minport )); then 11 | _minport=$_port 12 | fi 13 | done < ~/lib/vm/rdp-ports 14 | 15 | if (( ! port )); then 16 | port=$(( _minport+1 )) 17 | echo "$vm $port" >> ~/lib/vm/rdp-ports 18 | fi 19 | 20 | echo "Starting VM \"$vm\" on port $port" 21 | 22 | exec VBoxHeadless -s "$vm" -v on -e TCP/Ports="$port" 23 | -------------------------------------------------------------------------------- /misc/arch/fakepkg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | usage() { 6 | echo "Usage: ${0##*/} [-F] [-d package] " 7 | echo 8 | echo_opt "-F" "omit the -dummy suffix (shadow real package)" 9 | echo_opt "-d " "add a dependency (create a metapackage)" 10 | } 11 | 12 | suffix="-dummy" 13 | deps=() 14 | 15 | while getopts ":Fd:" OPT; do 16 | case $OPT in 17 | F) suffix="";; 18 | d) suffix=""; deps+=("$OPTARG");; 19 | *) lib:die_getopts;; 20 | esac 21 | done; shift $((OPTIND-1)) 22 | 23 | (( $# )) || die "no package names specified" 24 | 25 | if (( ${#deps[@]} )); then 26 | asdeps="" 27 | else 28 | asdeps="--asdeps" 29 | fi 30 | 31 | set -e 32 | workdir=$(mktemp -d /tmp/fakepkg.XXXXXXXXXX) 33 | cd "$workdir" 34 | for pkgname in "$@"; do 35 | pkgname=${pkgname@Q} 36 | if (( ${#deps[@]} )); then 37 | cat > PKGBUILD <<-! 38 | pkgname=$pkgname$suffix 39 | pkgdesc="Dummy metapackage" 40 | pkgver=0 41 | pkgrel=0 42 | arch=(any) 43 | depends=(${deps[@]@Q}) 44 | ! 45 | else 46 | cat > PKGBUILD <<-! 47 | pkgname=$pkgname$suffix 48 | pkgdesc="Dummy package providing "$pkgname 49 | pkgver=0 50 | pkgrel=0 51 | arch=(any) 52 | provides=($pkgname) 53 | replaces=($pkgname) 54 | conflicts=($pkgname) 55 | ! 56 | fi 57 | ${EDITOR:-vim} PKGBUILD 58 | makepkg --force --nosign --install $asdeps || true 59 | done 60 | cd / 61 | rm -rvf "$workdir" 62 | -------------------------------------------------------------------------------- /misc/arch/mkloaderconf.path: -------------------------------------------------------------------------------- 1 | # vim: ft=systemd 2 | [Unit] 3 | Description=Boot Kernel Configuration Watch 4 | 5 | [Path] 6 | PathChanged=/boot 7 | PathChanged=/etc/kernel/cmdline 8 | 9 | [Install] 10 | WantedBy=multi-user.target 11 | -------------------------------------------------------------------------------- /misc/arch/mkloaderconf.service: -------------------------------------------------------------------------------- 1 | # vim: ft=systemd 2 | [Unit] 3 | Description=Boot Kernel Configuration Update 4 | 5 | [Service] 6 | Type=oneshot 7 | ExecStart=/usr/local/bin/mkloaderconf 8 | -------------------------------------------------------------------------------- /misc/arch/pacverify: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | gzip -dc /var/lib/pacman/local/*/mtree | perl -ne 'if (s!^\.(/[^.]\S*) .+ sha256digest=(\w+).*!$2 *$1!) {s/\\(\d{3})/chr oct $1/ge; print}' | sudo sha256sum -c --quiet 4 | 5 | #gzip -dc /var/lib/pacman/local/*/mtree | perl -ane '($f, @f) = map {s/\\(\d{3})/chr oct $1/ge; $_} @F; $f =~ s/^\.//; %f = map {split /=/, $_, 2} @f; if ($f eq "/set") {%def = %f;} else {%f = (%def, %f); if ($f{sha256digest} && $f !~ /^\/\.[A-Z]+/) {print "$f{sha256digest} $f\n";}}' | sudo sha256sum -c 6 | -------------------------------------------------------------------------------- /misc/arch/pacwhy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Shows the chain of dependencies which causes package A to pull in package B. 3 | from functools import lru_cache 4 | from nullroute.misc import print_dependency_tree 5 | from pprint import pprint 6 | import subprocess 7 | import sys 8 | 9 | def enum_packages(): 10 | with subprocess.Popen(["pacman", "-Slq"], 11 | stdout=subprocess.PIPE) as proc: 12 | return {*proc.stdout.read().decode().split()} 13 | 14 | @lru_cache(maxsize=1024) 15 | def get_package_deps(pkg): 16 | with subprocess.Popen(["expac", "%E", pkg], 17 | stdout=subprocess.PIPE) as proc: 18 | return {*proc.stdout.read().decode().split()} 19 | 20 | def get_recursive_deps(pkg, seen=None): 21 | deps = {pkg} 22 | seen = seen or {pkg} 23 | for dep in get_package_deps(pkg) - seen: 24 | deps |= get_recursive_deps(dep, {*seen, dep}) 25 | return deps 26 | 27 | @lru_cache(maxsize=1024) 28 | def get_deps_with_rdep(pkg, rdep): 29 | return {x for x in get_package_deps(pkg) 30 | if rdep in get_recursive_deps(x)} 31 | 32 | def build_dep_tree(start, end): 33 | queue = {start} 34 | deps = {} 35 | while queue: 36 | pkg = queue.pop() 37 | deps[pkg] = get_deps_with_rdep(pkg, end) 38 | queue |= deps[pkg] - {*deps} 39 | return deps 40 | 41 | start = sys.argv[1] 42 | end = sys.argv[2] 43 | deps = build_dep_tree(start, end) 44 | print_dependency_tree(deps, start) 45 | -------------------------------------------------------------------------------- /misc/args.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | int i = 0; 5 | 6 | printf("argc = %d\n", argc); 7 | 8 | while (argv[i]) { 9 | printf("argv[%d] = %s\n", i, argv[i]); 10 | i++; 11 | } 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /misc/audit-decode-proctitle: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | perl -MSocket -pe ' 3 | s/(?<=(?:proctitle|name|exe|comm)=)([0-9A-F]+)/join " ", map {"\"$_\""} split("\0", $1 =~ s![0-9A-F]{2}!chr hex $&!ger)/ge; 4 | s/(?<=saddr=)(01[0-9A-F]+)/my ($addr) = unpack_sockaddr_un(pack("H*", $1)); $addr =~ s!^\0!@!; $addr/ge; 5 | s/(?<=saddr=)(02[0-9A-F]+)/my ($port, $addr) = unpack_sockaddr_in(pack("H*", $1)); inet_ntoa($addr).":".$port/ge; 6 | s/(?<=saddr=)(0A[0-9A-F]+)/my ($port, $addr, $scope) = unpack_sockaddr_in6(pack("H*", $1)); "[".inet_ntop(AF_INET6, $addr)."%".$scope."]:".$port/ge; 7 | ' 8 | -------------------------------------------------------------------------------- /misc/bird2names: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from functools import cache 3 | import re 4 | import socket 5 | import sys 6 | 7 | @cache 8 | def resolve(addr): 9 | try: 10 | name, _, _ = socket.gethostbyaddr(addr) 11 | name = name.removesuffix(".nullroute.lt") 12 | name = name.removeprefix("vlan147.") 13 | return name 14 | except socket.herror as e: 15 | print(f"error: Could not resolve {addr!r}: {e}", file=sys.stderr) 16 | return str(addr) 17 | 18 | for line in sys.stdin: 19 | line = line.rstrip().expandtabs() 20 | if m := re.match(r"^([0-9.]+)([ \t]+)(.+)$", line): 21 | addr, space, rest = m.groups() 22 | name = resolve(addr) 23 | width = len(addr + space) - 1 24 | if len(name) > width-2: 25 | name = name[:width-2] + ">" 26 | print(name.ljust(width), rest) 27 | else: 28 | print(line) 29 | -------------------------------------------------------------------------------- /misc/burn-iso: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | iso=$1 6 | 7 | [[ -s "$iso" ]] || die "image file not found: $iso" 8 | 9 | if have growisofs; then 10 | dev=/dev/cdrom 11 | growisofs -Z "$dev=$iso" 12 | elif have wodim; them 13 | wodim -sao "$iso" 14 | elif have cdrecord; then 15 | cdrecord -sao "$iso" 16 | elif have cdrdao; then 17 | toc=$(mktemp "/tmp/burn-XXXXXXXX.toc") || exit 18 | trap 'rm -f "$toc"; exit' INTR 19 | printf 'TRACK MODE1\nDATAFILE "%s"\n' "$iso" > "$toc" 20 | cdrdao write --overburn "$toc" 21 | rm -f "$toc" 22 | fi 23 | -------------------------------------------------------------------------------- /misc/cron.dropbatch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Note: systemd service expects this at ~/.local/bin/ 3 | 4 | PS4='+ ' 5 | 6 | log() { 7 | if [ -t 1 ]; then echo "$*"; fi 8 | } 9 | 10 | shopt -s nullglob 11 | 12 | for file in \ 13 | ~/Dropbox/${HOSTNAME%%.*}-*.sh \ 14 | ~/Dropbox/.System/Batch/${HOSTNAME%%.*}-*.sh ; 15 | do 16 | echo "Running job '$file'" 17 | { 18 | mv "$file" "$file.running" 19 | dos2unix -q "$file.running" 20 | { 21 | echo "--> $(date) ($HOSTNAME)" 22 | bash -x "$file.running" 2>&1 23 | echo "==> $?" 24 | } > "$file.log" 25 | mv "$file.running" "$file.done" 26 | } & 27 | done 28 | 29 | wait 30 | -------------------------------------------------------------------------------- /misc/ddrescue2dust.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Convert a ddrescue log to dm-dust badblock list 3 | import sys 4 | 5 | BS = 512 6 | dev = "dust1" 7 | 8 | # blockdev --getsz /dev/loop0 9 | # dmsetup create dust1 --table '0 488397168 dust /dev/loop0 0 512' 10 | # kpartx -u /dev/mapper/dust1 11 | 12 | print(f"dmsetup message {dev} 0 clearbadblocks") 13 | 14 | for line in sys.stdin: 15 | if line.startswith("0x"): 16 | start_byte, num_bytes, state = line.strip().split() 17 | if not num_bytes.startswith("0x"): 18 | # skip 'current' line 19 | continue 20 | if state != "-": 21 | continue 22 | start_byte = int(start_byte, 16) 23 | num_bytes = int(num_bytes, 16) 24 | if start_byte % BS: 25 | exit(f"start not mod {BS}: {line!r}") 26 | if num_bytes % BS: 27 | exit(f"count not mod {BS}: {line!r}") 28 | start_sector = start_byte // BS 29 | num_sectors = num_bytes // BS 30 | print(f"# {start_sector} +{num_sectors}") 31 | for i in range(num_sectors): 32 | print(f"dmsetup message {dev} 0 addbadblock {start_sector + i}") 33 | 34 | print(f"# end") 35 | print(f"dmsetup message {dev} 0 enable") 36 | -------------------------------------------------------------------------------- /misc/dejetty: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Jetty Deobfuscation Tool 3 | # https://stackoverflow.com/a/18861386/49849 4 | import argparse 5 | 6 | def deobfuscate_jetty(ciphertext): 7 | plaintext = "" 8 | for i in range(0, len(ciphertext), 4): 9 | t = ciphertext[i:i+4] 10 | i0 = int(t, 36) 11 | i1, i2 = divmod(i0, 256) 12 | x = (i1 + i2 - 254) >> 1 13 | plaintext += chr(x) 14 | return plaintext 15 | 16 | parser = argparse.ArgumentParser() 17 | parser.add_argument("string", nargs="+") 18 | args = parser.parse_args() 19 | 20 | for arg in args.string: 21 | print(deobfuscate_jetty(arg)) 22 | -------------------------------------------------------------------------------- /misc/do_rsync: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | declare src=$1 dest=$2 rest=("${@:3}") 6 | declare args=() 7 | 8 | # note: add -x to jobs instead of here 9 | args+=(nocache 10 | rsync "$src" "$dest" 11 | -aHAXvzh 12 | --info=progress2 13 | --delete-after 14 | --delete-excluded) 15 | 16 | for arg in "${rest[@]}"; do 17 | if [[ $last == -f && $arg == @(merge|.)\ * ]]; then 18 | debug "processing '$arg'" 19 | if [[ -f ${arg#* } ]]; then 20 | args+=("$arg") 21 | else 22 | debug "merge file not found, replacing with /dev/null" 23 | args+=("merge /dev/null") 24 | fi 25 | else 26 | args+=("$arg") 27 | fi 28 | last=$arg 29 | done 30 | 31 | echo "rsyncing $src -> $dest" >&2 32 | 33 | "${args[@]}"; r=$? 34 | 35 | (( !r )) || # success 36 | (( r == 24 )) # files vanished 37 | -------------------------------------------------------------------------------- /misc/dropbatch.path: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Dropbatch job monitor 3 | 4 | [Path] 5 | PathExistsGlob=%h/Dropbox/%H-*.sh 6 | PathExistsGlob=%h/Dropbox/.System/Batch/%H-*.sh 7 | 8 | [Install] 9 | WantedBy=paths.target 10 | -------------------------------------------------------------------------------- /misc/dropbatch.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Dropbatch job runner 3 | ConditionPathExistsGlob=|%h/Dropbox/%H-*.sh 4 | ConditionPathExistsGlob=|%h/Dropbox/.System/Batch/%H-*.sh 5 | 6 | [Service] 7 | Type=oneshot 8 | ExecStart=%h/bin/bin/cron.dropbatch 9 | KillMode=process 10 | -------------------------------------------------------------------------------- /misc/dropbatch.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Dropbatch job timer 3 | 4 | [Timer] 5 | OnCalendar=*:00/15:00 6 | 7 | [Install] 8 | WantedBy=timers.target 9 | -------------------------------------------------------------------------------- /misc/dxvk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | : ${WINEPREFIX:=~/.wine} 4 | 5 | case $1 in 6 | i|install) 7 | setup_dxvk install --without-dxgi --symlink 8 | ;; 9 | u|uninstall) 10 | setup_dxvk uninstall 11 | ;; 12 | esac 13 | 14 | cd "$WINEPREFIX/dosdevices" 15 | 16 | ls -l --color c:/windows/system32/{d3d{9,10,10_1,10core,11},dxgi}.dll 17 | -------------------------------------------------------------------------------- /misc/ecryptfs-mount-x11: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | _die() { 6 | zenity --error --title "" --text "$*" 7 | die "$*" 8 | } 9 | 10 | path="$HOME/Private" 11 | dpath=${path/#${HOME%/}'/'/'~/'} 12 | lock="$HOME/.ecryptfs/Private.mnt" 13 | 14 | if [[ $1 == "--nowait" ]]; then 15 | exec {fd}<"$lock" && flock -x -n $fd || 16 | die "another unlock prompt already running" 17 | else 18 | if mountpoint -q "$path"; then 19 | info "$dpath already mounted, exiting" 20 | exit 0 21 | else 22 | exec {fd}<"$lock" || exit 1 23 | # display unlock prompt if none running 24 | flock -x -n $fd && { 25 | flock -u $fd 26 | ecryptfs-mount-x11 --nowait 27 | } 28 | # wait for unlock 29 | exec flock -x $fd || exit 1 30 | fi 31 | fi 32 | 33 | pw=$(zenity --entry \ 34 | --title "Unlock private files" \ 35 | --text "Your private directory is locked.\n\nEnter password for $dpath" \ 36 | --hide-text \ 37 | --ok-label "Unlock" \ 38 | ) || exit 1 39 | 40 | wrapped=~/.ecryptfs/wrapped-passphrase 41 | 42 | # Twice. Sometimes it "forgets" to insert the FNEK. Fucker. 43 | printf '%s' "$pw" | ecryptfs-insert-wrapped-passphrase-into-keyring "$wrapped" - || 44 | _die "Failed to unlock your private files." 45 | #printf '%s\n' "$pw" | ecryptfs-insert-wrapped-passphrase-into-keyring "$wrapped" - || 46 | # _die "Failed to unlock your private files." 47 | ecryptfs-mount-private \$domain, 35 | ) || exit(2); 36 | 37 | for (@ARGV) { 38 | if (my @m = $_ =~ $re) { 39 | print to_dns(@m)."\n"; 40 | } else { 41 | warn "unrecognized input: '$_'\n"; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /misc/fujitsu-backlight: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The backlight percentages are rounded *down* to the nearest discrete value, 4 | # so on fujitsu we have to increment by 15% in order to reach the next higher 5 | # value, but decrementing by 15% actually results in going two values down. 6 | case $1 in 7 | +) exec xbacklight -inc 15%;; 8 | -) exec xbacklight -dec 1%;; 9 | esac 10 | -------------------------------------------------------------------------------- /misc/fujitsu-tablet-mode: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # "Tablet mode" handler for fujitsu tilt&rotate LCD panel 3 | # Activated by acpid on tablet-mode on/off, as well as following the 4 | # orientation change in 'rotate' button handler 5 | 6 | case $1 in 7 | -e|--enable) 8 | # Invoked by /etc/acpi/tablet-mode after LCD panel tilt into "tablet" mode 9 | # video/tabletmode:TBLT:*:00000001 10 | fujitsu-rotate-screen --tablet;; 11 | -d|--disable) 12 | # Invoked by /etc/acpi/tablet-mode after LCD panel tilt into "laptop" mode 13 | # video/tabletmode:TBLT:*:00000000 14 | fujitsu-rotate-screen --untablet;; 15 | *) 16 | echo "$0: bad args '$*'" >&2; exit 2;; 17 | esac 18 | -------------------------------------------------------------------------------- /misc/gai: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | from pprint import pprint 4 | import socket 5 | import sys 6 | 7 | def ifindex_to_ifname(idx): 8 | for ifname in os.listdir("/sys/class/net"): 9 | with open("/sys/class/net/%s/ifindex" % ifname, "r") as fh: 10 | if fh.read().strip() == str(idx): 11 | return ifname 12 | return str(idx) 13 | 14 | args = sys.argv[1:] 15 | 16 | for arg in args: 17 | r = socket.getaddrinfo(arg, 0, type=socket.SOCK_DGRAM) 18 | for (af, kind, proto, cname, addr) in r: 19 | if af == socket.AF_INET: 20 | (host, port) = addr 21 | addr = host 22 | elif af == socket.AF_INET6: 23 | (host, port, flow, scope) = addr 24 | if scope: 25 | addr = host + " % " + ifindex_to_ifname(scope) 26 | else: 27 | addr = host 28 | if af in {socket.AF_INET, socket.AF_INET6}: 29 | pass 30 | #addr = addr[0] 31 | print(af.name, "{", addr, "}") 32 | -------------------------------------------------------------------------------- /misc/gai.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use warnings; 3 | use strict; 4 | use Data::Dumper; 5 | use Socket qw(:addrinfo); 6 | 7 | sub do_resolve { 8 | my ($host) = @_; 9 | 10 | my $hints = {flags => AI_CANONNAME}; 11 | 12 | my ($err, @res) = getaddrinfo($host, undef, $hints); 13 | 14 | warn "fqdn: could not resolve '$host': $err\n" if $err; 15 | 16 | for my $res (@res) { 17 | my ($family_str, $addr_str); 18 | 19 | if ($res->{family} == Socket::AF_INET) { 20 | $family_str = "AF_INET"; 21 | my ($port, $addr) = Socket::unpack_sockaddr_in($res->{addr}); 22 | $addr_str = Socket::inet_ntop($res->{family}, $addr); 23 | } 24 | elsif ($res->{family} == Socket::AF_INET6) { 25 | $family_str = "AF_INET6"; 26 | my ($port, $addr, $scope, $flow) = Socket::unpack_sockaddr_in6($res->{addr}); 27 | $addr_str = Socket::inet_ntop($res->{family}, $addr); 28 | if ($scope) { $addr_str .= " % " . $scope; } 29 | } 30 | else { 31 | $family_str = "??"; 32 | } 33 | print "$family_str { $addr_str }\n"; 34 | } 35 | } 36 | 37 | do_resolve($_) for @ARGV; 38 | -------------------------------------------------------------------------------- /misc/gettime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include /* basename */ 5 | #include /* exit */ 6 | #include 7 | 8 | #ifndef CLOCK_BOOTTIME 9 | # define CLOCK_BOOTTIME -1 10 | #endif 11 | 12 | char *arg0; 13 | 14 | void usage(void) { 15 | printf("Usage: %s {-b | -m | -r}\n", arg0); 16 | exit(2); 17 | } 18 | 19 | int main(int argc, char *argv[]) { 20 | int r, opt, nsec = 0; 21 | clockid_t c = CLOCK_REALTIME; 22 | struct timespec t; 23 | 24 | arg0 = basename(argv[0]); 25 | 26 | while ((opt = getopt(argc, argv, "bmr")) != -1) { 27 | switch (opt) { 28 | case 'b': 29 | c = CLOCK_BOOTTIME; break; 30 | case 'm': 31 | c = CLOCK_MONOTONIC; break; 32 | case 'r': 33 | c = CLOCK_REALTIME; break; 34 | default: 35 | usage(); 36 | } 37 | } 38 | 39 | if (c == -1) 40 | errx(1, "requested clock is not supported on this system"); 41 | 42 | r = clock_gettime(c, &t); 43 | if (r < 0) 44 | err(1, "clock_gettime failed"); 45 | 46 | if (nsec) 47 | printf("%ld.%9lu\n", t.tv_sec, t.tv_nsec); 48 | else 49 | printf("%ld\n", t.tv_sec); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /misc/git-all-gc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # -l : do not pack "borrowed" objects 3 | # -d : remove redundant .packs 4 | # -a (-d) : pack everything into a single .pack 5 | # -A -d : same as -a -d, but unpack all unreachable objects 6 | find "${1:-.}" -name "*.git" -type d \ 7 | -exec test -e {}/config \; \ 8 | -prune \ 9 | -printf "Packing %p\n" \ 10 | -exec git -C {} gc \; 11 | -------------------------------------------------------------------------------- /misc/git-all-repack: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # -l : do not pack "borrowed" objects 3 | # -d : remove redundant .packs 4 | # -a (-d) : pack everything into a single .pack 5 | # -A -d : same as -a -d, but unpack all unreachable objects 6 | find "${1:-.}" -name "*.git" -type d \ 7 | -exec test -e {}/config \; \ 8 | -prune \ 9 | -printf "Packing %p\n" \ 10 | -exec git -C {} repack -l -d \; \ 11 | -exec git -C {} pack-refs --all --prune \; 12 | -------------------------------------------------------------------------------- /misc/git-branch-info: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # git-branch-info - verbose branch list 3 | git branch --all --no-color | 4 | sed -e 's/\*/ /' | 5 | while read branch; do 6 | branch=${branch%% *} 7 | ref=$branch 8 | case $ref in 9 | */HEAD) continue;; 10 | remotes/*) color='magenta'; branch=${branch#remotes/};; 11 | *) color='yellow';; 12 | esac 13 | git log -1 --format=format:"%C($color)${branch}%C(reset) %s %C(blue)(%cr)%C(reset)" "$ref" 14 | done 15 | -------------------------------------------------------------------------------- /misc/git-credential-netrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use warnings; 3 | use strict; 4 | use feature 'switch'; 5 | use Net::Netrc; 6 | 7 | sub usage { 8 | print "Usage: $0 \n"; 9 | exit 2; 10 | } 11 | 12 | sub lookup { 13 | my $res = Net::Netrc->lookup(@_); 14 | return defined $res->{machine} ? $res : undef; 15 | } 16 | 17 | sub find_best { 18 | my (%attr) = @_; 19 | 20 | my $res; 21 | 22 | if (!$res and defined $attr{protocol}) { 23 | $res = lookup($attr{protocol}.'@'.$attr{host}, $attr{username}); 24 | } 25 | if (!$res) { 26 | $res = lookup($attr{host}, $attr{username}); 27 | } 28 | if (!$res and defined $attr{protocol}) { 29 | $res = lookup($attr{protocol}.'@'.$attr{host}); 30 | } 31 | if (!$res) { 32 | $res = lookup($attr{host}); 33 | } 34 | 35 | if ($res) { 36 | return (username => $res->login, 37 | password => $res->password); 38 | } else { 39 | return; 40 | } 41 | } 42 | 43 | my $op = shift(@ARGV) // usage(); 44 | 45 | my %attr = map {chomp; split(/=/, $_, 2)} grep {/=/} ; 46 | 47 | if ($op eq "get") { 48 | my %cred = find_best(%attr); 49 | @attr{keys %cred} = map {$_ // ""} values %cred; 50 | print "$_=$attr{$_}\n" for sort keys %attr; 51 | } 52 | -------------------------------------------------------------------------------- /misc/git-credential-readonly: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use warnings; 3 | use strict; 4 | use Getopt::Long qw(:config bundling no_ignore_case); 5 | 6 | sub _warn { warn "$0: @_\n"; } 7 | 8 | my $opt_verbose = 0; 9 | my $opt_may_erase = 0; 10 | 11 | GetOptions( 12 | "v|verbose!" => \$opt_verbose, 13 | "e|erase!" => \$opt_may_erase, 14 | ); 15 | 16 | my ($helper, @args) = @ARGV; 17 | my $action = pop @ARGV; 18 | 19 | sub exec_helper { 20 | exec {"git"} "git", "credential-$helper", @args; 21 | } 22 | 23 | if ($action eq "get") { 24 | exec_helper(); 25 | } 26 | elsif ($action eq "store") { 27 | if ($opt_verbose) { 28 | _warn("ignoring store to credential-$helper"); 29 | } 30 | } 31 | elsif ($action eq "erase") { 32 | if ($opt_may_erase) { 33 | exec_helper(); 34 | } 35 | elsif ($opt_verbose) { 36 | _warn("ignoring erase from credential-$helper"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /misc/git-link-history: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # git-link-history - link history of two Git branches 3 | 4 | set -e 5 | 6 | if (( $# != 2 )); then 7 | echo "Usage: git link-history " 8 | echo "" 9 | echo "Prepend as a parent of the initial commit of ." 10 | exit 2 11 | fi 12 | 13 | newtail=$(git --no-replace-objects rev-list "$1^{commit}" | tail -1) 14 | oldhead=$(git --no-replace-objects rev-parse --verify "$2^{commit}") 15 | 16 | parent=$(git rev-parse --verify "$newtail^" 2>/dev/null || true) 17 | 18 | if [[ "$parent" ]]; then 19 | echo "error: initial commit of $1 already has a fake parent" 20 | exit 1 21 | else 22 | git replace --graft "$newtail" "$oldhead" 23 | git log -n 2 --decorate "$newtail" 24 | fi 25 | -------------------------------------------------------------------------------- /misc/gpgin: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | umask 077 4 | 5 | . lib.bash || exit 6 | 7 | case ${0##*/} in 8 | gpgin) mode=encrypt;; 9 | gpgout) mode=decrypt;; 10 | esac 11 | 12 | archive=$1 13 | name=${archive##*/} 14 | name=${name%.*} 15 | name=${name%.tar} 16 | 17 | options=() 18 | keydirs=( ~/Private/keys /run/media/grawity/grawpqi/Private/keys ) 19 | keybase="storage/archive-${name##*/}.key" 20 | 21 | keyfile= 22 | for dir in "${keydirs[@]}"; do 23 | if [[ -e "$dir/$keybase" ]]; then 24 | keyfile="$dir/$keybase" 25 | break 26 | fi 27 | done 28 | 29 | case $mode in 30 | encrypt) 31 | if [[ ! $keyfile ]]; then 32 | keyfile="${keydirs[0]}/$keybase" 33 | lib:echo "Generating keyfile: $keyfile" 34 | tr -dc "A-Za-z0-9" < /dev/urandom | head -c 64 > "$keyfile" 35 | fi 36 | options+=( --batch --passphrase-file "$keyfile" ) 37 | options+=( --no-tty ) 38 | gpg "${options[@]}" --symmetric \ 39 | | pv -N "gpg" > "$archive" 40 | ;; 41 | decrypt) 42 | if [[ ! $keyfile ]]; then 43 | die "key file not found" 44 | fi 45 | options+=( --batch --passphrase-file "$keyfile" ) 46 | options+=( --no-tty --no-mdc-warning ) 47 | pv -N "gpg" "$archive" \ 48 | | gpg "${options[@]}" --decrypt 49 | ;; 50 | esac 51 | -------------------------------------------------------------------------------- /misc/gpgout: -------------------------------------------------------------------------------- 1 | gpgin -------------------------------------------------------------------------------- /misc/hex.c: -------------------------------------------------------------------------------- 1 | /* hex -- convert data to hexadecimal */ 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | FILE *input = stdin; 8 | int opt; 9 | int c; 10 | 11 | while ((opt = getopt(argc, argv, "a:")) != -1) { 12 | switch (opt) { 13 | case 'a': 14 | input = fmemopen(optarg, strlen(optarg), "r"); 15 | break; 16 | default: 17 | return 2; 18 | } 19 | } 20 | 21 | if (argc > optind) { 22 | fprintf(stderr, "hex: too many arguments\n"); 23 | return 2; 24 | } 25 | 26 | for (;;) { 27 | c = fgetc(input); 28 | if (c == EOF) 29 | break; 30 | fprintf(stdout, "%02x", (unsigned char) c); 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /misc/hg-up: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # hg-up - update a hg repository and show changelog 3 | 4 | oldrev=$(hg tip -q) 5 | 6 | hg pull -u 7 | 8 | newrev=$(hg tip -q) 9 | 10 | if [[ "$oldrev" != "$newrev" ]]; then 11 | oldrev=${oldrev#*:} 12 | newrev=${newrev#*:} 13 | echo "Updated ${oldrev}:${newrev}" 14 | #hgk "${oldrev}:${newrev}" 15 | hg log -r "${oldrev}:${newrev}" --pager always 16 | fi 17 | -------------------------------------------------------------------------------- /misc/i3lock.fujitsu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #i3lock-fancy -g 4 | 5 | #i3lock -c 111111 -i ~/.dotfiles/gui/noise.png -t 6 | 7 | IMAGE="$HOME/.cache/i3lock.png" 8 | 9 | if [ "$0" -nt "$IMAGE" ]; then 10 | rm -f "$IMAGE" 11 | bg=111111 12 | noise=~/.dotfiles/gui/noise.png 13 | 14 | res=$(xdpyinfo | awk '/dimensions:/ {print $2}') 15 | xres=${res%x*} 16 | yres=${res#*x} 17 | 18 | W=$xres H=$yres Xoff=0 Yoff=0 19 | MIDXi=$(($W / 2 + $Xoff - 60 / 2)) 20 | MIDYi=$(($H / 2 + $Yoff - 60 / 2)) 21 | MIDXt=$(($W / 2 + $Xoff - 285 / 2)) 22 | MIDYt=$(($H / 2 + $Yoff + 320 / 2)) 23 | LOCK=() 24 | FONT=Arimo 25 | TEXT="Type password to unlock" 26 | ICON=/usr/share/i3lock-fancy/lock.png 27 | LOCK+=(-font "$FONT" -pointsize 26 28 | #-fill lightgrey -stroke grey10 -strokewidth 2 -annotate +$MIDXt+$MIDYt "$TEXT" 29 | #-fill lightgrey -stroke lightgrey -strokewidth 1 -annotate +$MIDXt+$MIDYt "$TEXT" 30 | #-fill grey60 -annotate +$MIDXt+$MIDYt "$TEXT" 31 | "$ICON" -geometry +$MIDXi+$MIDYi -composite) 32 | set -x 33 | magick convert "$noise" -background "#$bg" -flatten /tmp/tile.png 34 | magick convert -size "${xres}x${yres}" tile:/tmp/tile.png "$IMAGE" 35 | magick convert "$IMAGE" "${LOCK[@]}" "$IMAGE" 36 | fi 37 | 38 | i3lock -n -i "$IMAGE" -e -f 39 | -------------------------------------------------------------------------------- /misc/id3-purge-priv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | from __future__ import print_function 3 | import sys 4 | import mutagen.mp3 5 | 6 | if sys.argv[1] == "-r": 7 | remove = True 8 | sys.argv.pop(1) 9 | else: 10 | remove = False 11 | 12 | args = sys.argv[1:] 13 | for fname in args: 14 | ftag = mutagen.mp3.MP3(fname) 15 | 16 | frames = [key for key in ftag if key.startswith(u"PRIV:")] 17 | 18 | if len(frames): 19 | print("-- %s" % fname) 20 | else: 21 | continue 22 | 23 | frames.sort() 24 | 25 | for name in frames: 26 | frame = ftag[name] 27 | print(repr(frame)) 28 | if remove: 29 | del ftag[name] 30 | 31 | if remove: 32 | ftag.save() 33 | -------------------------------------------------------------------------------- /misc/id3-sync-rg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # id3-sync-rg - copy ReplayGain tags from RVA2 to foobar2000 3 | import argparse 4 | import mutagen.mp3 5 | import sys 6 | from nullroute.mp3tags import GainValue 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument("file", nargs="+") 10 | args = parser.parse_args() 11 | 12 | for file in args.file: 13 | print("updating %s" % file) 14 | ftag = mutagen.mp3.MP3(file) 15 | 16 | trackgain = GainValue.import_tag(ftag, 'track') 17 | if trackgain: 18 | #print trackgain 19 | trackgain.export_id3(ftag) 20 | 21 | albumgain = GainValue.import_tag(ftag, 'album') 22 | if albumgain: 23 | #print albumgain 24 | albumgain.export_id3(ftag) 25 | 26 | if trackgain or albumgain: 27 | ftag.save() 28 | -------------------------------------------------------------------------------- /misc/import-arch-keyring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # import-arch-keyring -- import Arch Linux developer keys into GnuPG 3 | 4 | . lib.bash || exit 5 | 6 | dir=/usr/share/pacman/keyrings 7 | rings=archlinux 8 | 9 | TRUST_ULTIMATE=6 10 | TRUST_FULL=5 11 | TRUST_MARGINAL=4 12 | TRUST_NONE=3 13 | TRUST_DONTKNOW=2 14 | 15 | for ring in $rings; do 16 | log2 "importing keyring" 17 | gpg --no-auto-check-trustdb \ 18 | --key-origin "url,https://www.archlinux.org/master-keys/" \ 19 | --import "$dir/$ring.gpg" || exit 20 | 21 | revoked=$(< "$dir/$ring-revoked") 22 | trusted=$(awk -F: '{print $1}' "$dir/$ring-trusted") 23 | 24 | log2 "refreshing revoked keys" 25 | gpg --no-auto-check-trustdb --recv-keys $revoked 26 | 27 | log2 "locally signing master keys" 28 | if confirm "proceed with lsign-key?"; then 29 | for k in $trusted; do 30 | gpg --no-auto-check-trustdb --quick-lsign-key "$k" 31 | done 32 | fi 33 | 34 | log2 "setting master keys to marginal trust" 35 | for k in $trusted; do 36 | echo "$k:$TRUST_MARGINAL:" 37 | done | gpg --no-auto-check-trustdb --import-ownertrust 38 | done 39 | 40 | log2 "updating trustdb" 41 | gpg --check-trustdb 42 | -------------------------------------------------------------------------------- /misc/irssi/auth_webirc.pl: -------------------------------------------------------------------------------- 1 | # vim: ft=perl 2 | use strict; 3 | use Irssi; 4 | 5 | our $VERSION = "0.8"; 6 | our %IRSSI = ( 7 | name => 'auth_webirc.pl', 8 | description => 'Implements WEBIRC authentication for UnrealIRCd', 9 | license => 'MIT (Expat) ', 10 | ); 11 | 12 | my %networks; 13 | 14 | sub load_networks { 15 | my $path = Irssi::get_irssi_dir . "/webirc.auth"; 16 | if (open(my $fh, "<", $path)) { 17 | my $tag; 18 | while (<$fh>) { 19 | if (/^[#;]/) { 20 | next; 21 | } elsif (/^(\w+)$/) { 22 | $networks{$tag = $1} = {}; 23 | } elsif (/^\s+(\w+?)=(.+)$/) { 24 | $networks{$tag}{$1} = $2; 25 | } else { 26 | warn "webirc.auth:$.: parse error: $_"; 27 | } 28 | } 29 | close($fh); 30 | } 31 | } 32 | 33 | Irssi::signal_add_last("server connected" => sub { 34 | my ($server) = @_; 35 | my $tag = lc $server->{tag}; 36 | if (defined $networks{$tag}) { 37 | my %d = %{$networks{$tag}}; 38 | if (exists $d{host} and exists $d{pass} and exists $d{ipaddr}) { 39 | $server->print("", "Setting $d{host} as hostname"); 40 | $server->send_raw_now("WEBIRC $d{pass} cgiirc $d{host} :$d{ipaddr}"); 41 | } 42 | } 43 | }); 44 | 45 | load_networks(); 46 | -------------------------------------------------------------------------------- /misc/irssi/coffee.pl: -------------------------------------------------------------------------------- 1 | use strict; 2 | use utf8; 3 | use Irssi; 4 | 5 | our $VERSION = '0.3'; 6 | our %IRSSI = ( 7 | name => 'spacefail', 8 | description => 'Warns you if you have extra spaces before /command', 9 | contact => 'Mantas Mikulėnas ', 10 | license => 'MIT (Expat) ', 11 | ); 12 | 13 | Irssi::signal_add("send text" => sub { 14 | my ($line, $server, $witem) = @_; 15 | 16 | $witem //= Irssi::active_win; 17 | if ($line =~ m|^\s+/(\w+)|) { 18 | $witem->command("scrollback end"); 19 | $witem->print("Stopped command \002/$1\002 from being sent to channel.", MSGLEVEL_CLIENTERROR); 20 | Irssi::signal_stop; 21 | } 22 | elsif ($line eq 'ls') { 23 | $witem->command("names"); 24 | Irssi::signal_stop; 25 | } 26 | elsif ($line =~ /^[:;]w?q$/) { 27 | $witem->print("This is not Vi."); 28 | Irssi::signal_stop; 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /misc/irssi/scrollwarn.pl: -------------------------------------------------------------------------------- 1 | use strict; 2 | use utf8; 3 | use Irssi; 4 | use Irssi::TextUI; 5 | 6 | our $VERSION = '0.4'; 7 | our %IRSSI = ( 8 | name => 'scrollwarn', 9 | description => 'Warns you if you were scrolled up when sending a message.', 10 | contact => 'Mantas Mikulėnas ', 11 | license => 'MIT (Expat) ', 12 | ); 13 | 14 | Irssi::signal_add("send text" => sub { 15 | my ($line, $server, $witem) = @_; 16 | 17 | my $win = Irssi::active_win; 18 | my $view = $win->view; 19 | if (!$view->{bottom}) { 20 | my $lines = $view->{ypos} - $view->{height}; 21 | $win->command("scrollback end"); 22 | $win->print("You were scrolled up by $lines lines. Message not sent.", MSGLEVEL_CLIENTERROR); 23 | Irssi::signal_stop; 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /misc/is-attached: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # is-attached -- check whether a Mosh session is currently attached to a live client 3 | use Sys::Utmp qw(:constants); 4 | 5 | use constant { 6 | EX_ATTACHED => 0, 7 | EX_DETACHED => 1, 8 | }; 9 | 10 | my $verbose = ($ARGV[0] eq "-v"); 11 | 12 | my @ttys; 13 | 14 | if (open(my $fh, "-|", "tmux", "list-clients", "-t", "irc")) { 15 | @ttys = map {m[^/dev/(.+?): ] and $1} <$fh>; 16 | close($fh); 17 | } 18 | 19 | if (@ttys) { 20 | # tmux session has clients attached 21 | # ignore those belonging to detached mosh sessions 22 | my %ttys = map {$_ => 1} @ttys; 23 | my $re = qr/^mosh \[\d+\]$/; 24 | my $utmp = Sys::Utmp->new; 25 | while (my $ut = $utmp->getutent) { 26 | my $t = $ut->ut_line; 27 | if ($ut->ut_type == USER_PROCESS && $ttys{$t}) { 28 | # this belongs to our tmux session 29 | my $h = $ut->ut_host; 30 | if ($h =~ $re) { 31 | # this is a detached mosh session, ignore 32 | print "line $t is detached: $h\n" if $verbose; 33 | delete $ttys{$t}; 34 | } else { 35 | print "line $t is attached: $h\n" if $verbose; 36 | } 37 | } 38 | } 39 | @ttys = keys %ttys; 40 | } 41 | 42 | exit(@ttys ? EX_ATTACHED : EX_DETACHED); 43 | -------------------------------------------------------------------------------- /misc/libfunsync.c: -------------------------------------------------------------------------------- 1 | /* libfunsync - preload library to prevent svnsync from calling fsync() for 2 | * every revision, as it only slows down operations greatly */ 3 | 4 | void sync(void) { 5 | return; 6 | } 7 | 8 | int fsync(int fd) { 9 | return 0; 10 | } 11 | 12 | int fdatasync(int fd) { 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /misc/lsdefines: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cpp -dM /dev/null | sort 3 | -------------------------------------------------------------------------------- /misc/maildir-layout: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Converts between "normal" and "filesystem" Maildir layouts. 3 | # 4 | # Normal: ~/mail/ 5 | # ~/mail/.lists/ 6 | # ~/mail/.lists.nanog/ 7 | # 8 | # Filesystem: ~/mail/ 9 | # ~/mail/lists/ 10 | # ~/mail/lists/nanog/ 11 | 12 | . lib.bash || exit 13 | 14 | usage() { 15 | echo "Usage: $progname [-d basedir] {-f | -t}" 16 | echo "" 17 | echo " -d basedir Use basedir instead of ~/mail/" 18 | echo " -f Convert from filesystem layout" 19 | echo " -t Convert to filesystem layout" 20 | } 21 | 22 | from-fs() { 23 | find "$maildir" -mindepth 1 -depth -type d -not \( \ 24 | -name ".*" -o -name "cur" -o -name "new" -o -name "tmp" \) \ 25 | -printf "%P\0" | while IFS="" read -rd "" dir; do 26 | new=".${dir//\//.}" 27 | mv -v "$maildir/$dir" "$maildir/$new" 28 | done 29 | } 30 | 31 | to-fs() { 32 | find "$maildir" -mindepth 1 -type d -name ".*" \ 33 | -printf "%P\0" | LC_COLLATE="C" sort -z |\ 34 | while IFS="" read -rd "" dir; do 35 | new="${dir#.}" 36 | new="${new//.//}" 37 | mv -v "$maildir/$dir" "$maildir/$new" 38 | done 39 | } 40 | 41 | maildir=~/mail 42 | mode= 43 | 44 | while getopts ":d:ft" OPT; do 45 | case $OPT in 46 | d) maildir=$OPTARG;; 47 | f) mode=from;; 48 | t) mode=to;; 49 | *) lib:die_getopts;; 50 | esac 51 | done 52 | 53 | case $mode in 54 | from) from-fs;; 55 | to) to-fs;; 56 | *) die "must specify conversion mode";; 57 | esac 58 | -------------------------------------------------------------------------------- /misc/mime-attach: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | import email 4 | import email.policy 5 | import os 6 | import sys 7 | import subprocess 8 | import mimetypes 9 | 10 | parser = argparse.ArgumentParser() 11 | parser.add_argument("file", nargs="+") 12 | args = parser.parse_args() 13 | 14 | msg = email.message_from_file(sys.stdin, 15 | policy=email.policy.default) 16 | 17 | for arg in args.file: 18 | name = os.path.basename(arg) 19 | mime = mimetypes.guess_type(arg)[0] or "text/plain" 20 | buf = open(arg, "rb").read() 21 | msg.add_attachment(buf, *mime.split("/"), filename=name) 22 | 23 | had_from = msg.get_unixfrom() 24 | print(msg.as_string(unixfrom=had_from)) 25 | -------------------------------------------------------------------------------- /misc/mutagen-ls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | import mutagen 4 | import sys 5 | 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument("file", nargs="+") 8 | args = parser.parse_args() 9 | 10 | for file in args.file: 11 | tags = mutagen.File(file) 12 | if tags: 13 | artist = None 14 | if "TPE1" in tags: 15 | artist = tags["TPE1"] 16 | else: 17 | pass 18 | title = None 19 | if "TIT2" in tags: 20 | title = tags["TIT2"] 21 | else: 22 | pass 23 | if artist or title: 24 | artist = artist or "[Unknown artist]" 25 | title = title or "[Unknown title]" 26 | print("%s: %s - %s" % (file, artist, title)) 27 | -------------------------------------------------------------------------------- /misc/nextfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # nextfile -- output an unique filename ("date.nnn" or "prefix - date.nnn") 3 | 4 | . lib.bash || exit 5 | 6 | suffix="" 7 | sep="." 8 | opt_date=0 9 | 10 | while getopts ":ds:S:" OPT; do 11 | case $OPT in 12 | d) opt_date=1;; 13 | s) suffix=$OPTARG;; 14 | S) sep=$OPTARG;; 15 | *) lib:die_getopts;; 16 | esac 17 | done; shift $((OPTIND-1)) 18 | 19 | prefix="$1" 20 | if [[ ! $suffix ]]; then 21 | suffix=${prefix##*.} 22 | prefix=${prefix%.*} 23 | fi 24 | prefix="${prefix:+$prefix$sep}" 25 | 26 | date=$(date +"%Y-%m-%d") 27 | dir="." 28 | 29 | for (( count=0; count < 999; count++ )); do 30 | if (( opt_date )); then 31 | printf -v name "%s%s.%03d.%s" "$prefix" "$date" "$count" "$suffix" 32 | else 33 | printf -v name "%s%03d.%s" "$prefix" "$count" "$suffix" 34 | fi 35 | if [[ ! -e $dir/$name && ! -e $dir/.$name.tmp ]]; then 36 | echo "$dir/$name" 37 | exit 0 38 | fi 39 | done 40 | 41 | die "could not find an unique filename" 42 | -------------------------------------------------------------------------------- /misc/nfreload: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | have() { command -v "$1" >/dev/null 2>&1; } 4 | 5 | klog() { 6 | # Nspawn containers don't have kmsg 7 | if [[ -c /dev/kmsg ]]; then 8 | echo "nftables: $*" > /dev/kmsg 9 | else 10 | logger -t nftables -- "$*" 11 | fi 12 | } 13 | 14 | set -e 15 | umask 077 16 | 17 | if ! grep -qs '^flush ruleset$' /etc/nftables.conf; then 18 | # We *could* handle it by using 'include' like nftables.service does 19 | echo "$0: current config is not atomic; refusing to reload" >&2 20 | exit 1 21 | fi 22 | 23 | err=0 24 | old=$(mktemp /tmp/nftables.old.XXXXXXXX) 25 | new=$(mktemp /tmp/nftables.new.XXXXXXXX) 26 | 27 | nft list ruleset > "$old" 28 | #nft 'flush ruleset; include "/etc/nftables.conf"' || err=1 29 | nft -f /etc/nftables.conf || err=1 30 | nft list ruleset > "$new" 31 | 32 | if (( ! err )); then 33 | klog "reloaded by ${SUDO_USER:-${USER:-(service)}}" 34 | 35 | if have git; then 36 | git diff --no-index -- "$old" "$new" || true 37 | elif have colordiff; then 38 | colordiff -u "$old" "$new" || true 39 | elif have tig; then 40 | diff -u "$old" "$new" | tig 41 | elif have diff; then 42 | diff -u "$old" "$new" || true 43 | else 44 | echo "$0: successfully reloaded, but no diff tool available" >&2 45 | err=1 46 | fi 47 | fi 48 | 49 | rm -f "$old" "$new" 50 | exit $err 51 | -------------------------------------------------------------------------------- /misc/obsolete/reconfigure: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # reconfigure -- try to run ./configure with the last used options 3 | 4 | if [[ configure.ac -nt configure ]] || 5 | [[ configure.in -nt configure ]] || 6 | [[ autogen.sh -nt configure ]]; then 7 | if [[ -x autogen.sh ]]; then 8 | (NOCONFIGURE=1 ./autogen.sh) 9 | elif [[ -e autogen.sh ]]; then 10 | (NOCONFIGURE=1 sh ./autogen.sh) 11 | else 12 | (autoreconf -fi) 13 | fi 14 | fi 15 | 16 | if [[ -e config.log ]] && ! (( $# )); then 17 | sed -n '/^ \$ /{s///;p;q}' config.log | sh 18 | else 19 | (./configure --prefix="$PREFIX" "$@") 20 | fi 21 | -------------------------------------------------------------------------------- /misc/obsolete/session-chooser: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | default='gnome-session' 4 | 5 | sessions=" 6 | systemd systemd-user 7 | GNOME gnome-session 8 | Openbox openbox-session 9 | KDE startkde 10 | wmii wmii 11 | Xterm xterm 12 | " 13 | 14 | list_sessions() { 15 | printf '%s\n' $sessions 16 | exit 17 | for f in /usr/share/xsessions/*.desktop; do 18 | name=`awk -F'=' '$1 == "Name" {print $2}' "$f"` 19 | cmd=`awk -F'=' '$1 == "Exec" {print $2}' "$f"` 20 | printf '%s\t%s\n' "$name" "$cmd" 21 | done | sort | tr '\t' '\n' 22 | } 23 | 24 | selector() { 25 | zenity --list \ 26 | --title="Logon session" \ 27 | --text="Select X11 session:" \ 28 | --column="Session" \ 29 | --column="Command" \ 30 | --hide-column=2 \ 31 | --hide-header \ 32 | --print-column=ALL \ 33 | --separator=' ' \ 34 | --height=250 \ 35 | --ok-label="Login" \ 36 | --cancel-label="Exit" \ 37 | --timeout=5 \ 38 | ; 39 | } 40 | 41 | out=$(list_sessions | selector) || exit 42 | set -- ${out:-default $default} 43 | session=$1 44 | command=$2 45 | 46 | export DESKTOP_SESSION=${session,,} 47 | exec $command 48 | -------------------------------------------------------------------------------- /misc/obsolete/unburst: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Convert a Sony camera 4x4-tile "burst" photo to a 16-frame gif 3 | 4 | for input; do 5 | base=${input%.*} 6 | convert -crop "25%x25%" "$input" +repage "$base".tile%02d.png 7 | mogrify +repage "$base".tile*.png 8 | convert -loop 1 -delay 10 "$base".tile*.png "$base".gif 9 | rm "$base".tile*.png 10 | done 11 | -------------------------------------------------------------------------------- /misc/pacman-verify: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | root="" 6 | dbpath="$root/var/lib/pacman/local" 7 | 8 | if (( $# )); then 9 | dirs=() 10 | for _pkg in "$@"; do 11 | dirs+=("$dbpath"/$_pkg-*/) 12 | done 13 | else 14 | dirs=("$dbpath"/*/) 15 | fi 16 | 17 | for dir in "${dirs[@]}"; do 18 | pkg=${dir%/} 19 | pkg=${pkg##*/} 20 | 21 | if ! [[ -s "$dir/mtree" ]]; then 22 | warn "package '$pkg' is missing a mtree file" 23 | continue 24 | fi 25 | 26 | while read -r name rest; do 27 | if [[ $name == ./.@(BUILDINFO|CHANGELOG|INSTALL|PKGINFO) ]]; then 28 | continue 29 | fi 30 | name=/${name#./} 31 | if [[ $name == *\\* && $name != *\\@(12|012)* ]]; then 32 | # spaces and UTF-8 symbols are octal-encoded 33 | # (safeguard: do not decode if it contains a \n) 34 | name=$(unescape -a "$name") 35 | fi 36 | for arg in $rest; do 37 | k=${arg%%=*} 38 | v=${arg#*=} 39 | case $k in 40 | sha256digest) 41 | printf '%s %s\n' "$v" "$name" 42 | ;; 43 | esac 44 | done 45 | done < <(gzip -d < "$dir/mtree") 46 | done 47 | -------------------------------------------------------------------------------- /misc/pause.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) { 4 | pause(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /misc/perl-lspkgs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # perl-lspkgs - list locally installed Perl packages 3 | 4 | sub _debug { 5 | warn "@_\n" if $ENV{DEBUG}; 6 | } 7 | 8 | my %pkgs; 9 | 10 | for my $dir (@INC) { 11 | _debug("reading '$dir/perllocal.pod'"); 12 | open(my $fh, "<", "$dir/perllocal.pod") or next; 13 | while (<$fh>) { 14 | if (/^=head2 .+ L<(.+)\|.+>$/) { 15 | $pkg = $1; 16 | next if $pkgs{$pkg}++; 17 | if ($pkg eq 'ack') {$pkg = 'App::Ack'} 18 | if ($pkg eq 'rdapper') {next} 19 | print "$pkg\n"; 20 | } 21 | } 22 | close($fh); 23 | } 24 | -------------------------------------------------------------------------------- /misc/perl-packlist: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # perl-packlist - list contents of a Perl package 3 | 4 | my $err = 0; 5 | 6 | for my $pkg (@ARGV) { 7 | $pkg =~ s|::|/|g; 8 | 9 | my @packs = 10 | grep {-e} 11 | map {$_."/".$pkg."/.packlist"} 12 | map {$_, $_."/auto"} @INC; 13 | 14 | for my $pack (@packs) { 15 | if (open($pf, "<", $pack)) { 16 | print for <$pf>; 17 | close($pf); 18 | } 19 | print "$pack\n"; 20 | } 21 | 22 | if (!@packs) { 23 | warn "can't find packlist for $pkg\n"; ++$err; 24 | } 25 | } 26 | 27 | exit !!$err; 28 | -------------------------------------------------------------------------------- /misc/perl-rebuild: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | pkgs=$(perl-lspkgs) 6 | 7 | echo "Local packages:" 8 | 9 | printf " * %s\n" $pkgs | sort 10 | 11 | if confirm "Rebuild?"; then 12 | echo $pkgs | xargs cpanm -f 13 | fi 14 | -------------------------------------------------------------------------------- /misc/perl-where: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # perl-where - show full path of a Perl module, like 'which' 3 | 4 | my $err = 0; 5 | 6 | for my $pkg (@ARGV) { 7 | $pkg =~ s|::|/|g; 8 | 9 | my @files = grep {-f} map {"$_/$pkg.pm"} @INC; 10 | 11 | if (@files) { 12 | print "$_\n" for @files; 13 | } else { 14 | warn "can't find $pkg.pm\n"; ++$err; 15 | } 16 | } 17 | 18 | exit !!$err; 19 | -------------------------------------------------------------------------------- /misc/pyrebuild: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | pacaur -u --rebuild $(pacman -Qqm | grep ^python-) 6 | -------------------------------------------------------------------------------- /misc/rebuild-parttable.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -t 1 ]]; then 4 | c=('\e[1;30m' '\e[32m' '\e[34m' '\e[35m' '\e[36m' '\e[m') 5 | else 6 | c=() 7 | fi 8 | 9 | dev=${1:-sda} 10 | dev=${dev#/dev/} 11 | 12 | echo "#!/bin/sh -ex" 13 | 14 | for part in /sys/class/block/${dev}[0-9]*; do 15 | num=$(<$part/partition) 16 | start=$(<$part/start) 17 | size=$(<$part/size) 18 | end=$((start+size-1)) 19 | echo -e "\n${c[0]}# partition ${c[1]}$num${c[0]}, start ${c[2]}$start${c[0]}, size ${c[3]}$size${c[0]}, end ${c[4]}$end${c[0]}${c[5]}\n" 20 | echo "sgdisk /dev/$dev --new=$num:$start:$end" 21 | #echo "parted /dev/$dev mkpart primary ${start}s ${end}s" 22 | done 23 | -------------------------------------------------------------------------------- /misc/reverse-ident: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use IO::Socket::INET; 3 | 4 | my ($host, $port) = @ARGV; 5 | 6 | die "Usage: $0 \n" if !($host && $port); 7 | 8 | my $mainsock = IO::Socket::INET->new 9 | (PeerAddr => $host, 10 | PeerPort => $port, 11 | Proto => "tcp"); 12 | 13 | die "Could not connect to service: $@\n" if !$mainsock; 14 | 15 | my $lh = $mainsock->sockhost; 16 | my $lp = $mainsock->sockport; 17 | my $rh = $mainsock->peerhost; 18 | my $rp = $mainsock->peerport; 19 | 20 | print "Connected to service: [$lh]:$lp <--> [$rh]:$rp\n"; 21 | 22 | my $identsock = IO::Socket::INET->new 23 | (PeerAddr => $rh, 24 | PeerPort => "113", 25 | LocalAddr => $lh, 26 | Proto => "tcp"); 27 | 28 | die "Could not connect to identd: $@\n" if !$identsock; 29 | 30 | print "Reached identd at: [$rh]:113\n"; 31 | 32 | print {$identsock} "$rp,$lp\r\n"; 33 | $identsock->flush; 34 | 35 | print "Received reply: $_" while <$identsock>; 36 | -------------------------------------------------------------------------------- /misc/rg-copytags: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copy ReplayGain tags from various formats to MP3 (for iPod downconversion; 3 | # ffmpeg does not copy RVA2 automatically) 4 | import argparse 5 | import mutagen 6 | import sys 7 | from nullroute.mp3tags import GainValue 8 | 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("src_file") 11 | parser.add_argument("dst_file") 12 | args = parser.parse_args() 13 | 14 | srctag = mutagen.File(args.src_file) 15 | dsttag = mutagen.mp3.MP3(args.dst_file) 16 | 17 | gv = GainValue.import_tag(srctag, 'track') 18 | if not gv: 19 | print("No ReplayGain tag found in %r" % args.src_file, file=sys.stderr) 20 | print(srctag) 21 | exit(1) 22 | 23 | gv.export_id3(dsttag) 24 | dsttag.save() 25 | -------------------------------------------------------------------------------- /misc/rotate-laptop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # rotate-laptop -- rotate the screen and touchpad at the same time 3 | 4 | . lib.bash || exit 5 | 6 | dir=$1 7 | 8 | case $dir in 9 | n|normal|u|up|default|reset) 10 | dir=normal;; 11 | l|left) 12 | dir='left';; 13 | r|right) 14 | dir='right';; 15 | i|inverted|d|down) 16 | dir='inverted';; 17 | '') 18 | die "missing direction";; 19 | *) 20 | die "bad direction '$dir'";; 21 | esac 22 | 23 | case $dir in 24 | normal) 25 | coords=( 1 0 0 26 | 0 1 0 27 | 0 0 1);; 28 | left) 29 | coords=( 0 -1 1 30 | 1 0 0 31 | 0 0 1);; 32 | right) 33 | coords=( 0 1 0 34 | -1 0 1 35 | 0 0 1);; 36 | inverted) 37 | coords=(-1 0 1 38 | 0 -1 1 39 | 0 0 1);; 40 | esac 41 | 42 | xrandr -o $dir 43 | 44 | xinput set-prop "ETPS/2 Elantech Touchpad" \ 45 | "Coordinate Transformation Matrix" \ 46 | ${coords[@]} 47 | -------------------------------------------------------------------------------- /misc/rtf2html: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use RTF::HTML::Converter; 3 | 4 | RTF::HTML::Converter->new(output => \*STDOUT)->parse_stream(\*STDIN); 5 | -------------------------------------------------------------------------------- /misc/rups: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # rups -- launch iText-RUPS PDF inspector 3 | v=5.5.9 4 | exec java -jar ~/.local/lib/itext-rups-$v-jar-with-dependencies.jar "$@" 5 | -------------------------------------------------------------------------------- /misc/sign-exe: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | cert="" 6 | nssdb="sql:$HOME/.pki/nssdb" 7 | force=0 8 | 9 | have pesign || err "missing 'pesign' tool" 10 | (( ! errors )) || exit 11 | 12 | while getopts ":c:d:f" OPT; do 13 | case $OPT in 14 | c) cert=$OPTARG;; 15 | d) nssdb=$OPTARG;; 16 | f) force=1;; 17 | *) lib:die_getopts;; 18 | esac 19 | done; shift $((OPTIND-1)) 20 | 21 | if [[ ! $cert ]]; then 22 | die "certificate name not specified" 23 | fi 24 | 25 | in_file=$1 26 | 27 | if [[ ! $in_file ]]; then 28 | die "input file not specified" 29 | fi 30 | 31 | if [[ ! -f $in_file ]]; then 32 | die "input file '$in_file' does not exist" 33 | fi 34 | 35 | out_file=${in_file%.*}-signed.${in_file##*.} 36 | 37 | if [[ -e $out_file ]] && (( ! force )); then 38 | die "output file '$out_file' already exists" 39 | fi 40 | 41 | pesign --verbose \ 42 | --certdir="$nssdb" \ 43 | --certficate="$cert" \ 44 | --in="$in_file" \ 45 | --out="$out_file" \ 46 | --sign 47 | 48 | lib:echo "Created \"$out_file\"" 49 | -------------------------------------------------------------------------------- /misc/sign-xpi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # sign-xpi -- sign Mozilla XPI addon/extension archives 3 | 4 | . lib.bash || exit 5 | 6 | cert="" 7 | nssdb="sql:$HOME/.pki/nssdb" 8 | force=0 9 | do_list=0 10 | 11 | have signtool || err "missing 'signtool' from NSS" 12 | have zip || err "missing 'zip' tool" 13 | (( ! errors )) || exit 14 | 15 | while getopts ":c:d:fl" OPT; do 16 | case $OPT in 17 | c) cert=$OPTARG;; 18 | d) nssdb=$OPTARG;; 19 | f) force=1;; 20 | l) do_list=1;; 21 | *) lib:die_getopts;; 22 | esac 23 | done; shift $((OPTIND-1)) 24 | 25 | if (( do_list )); then 26 | signtool -d "$nssdb" -l 27 | exit 28 | fi 29 | 30 | if [[ ! $cert ]]; then 31 | die "certificate name (-c) not specified" 32 | fi 33 | 34 | if [[ ! -f install.rdf ]]; then 35 | die "current directory does not contain a valid Mozilla extension" 36 | fi 37 | 38 | out_file="${1:-${PWD##*/}}.xpi" 39 | 40 | (shopt -s nullglob; rm -f *.xpi) 41 | 42 | signtool -d "$nssdb" -k "$cert" -Z "$out_file" . 43 | 44 | lib:echo "Created \"$out_file\"" 45 | -------------------------------------------------------------------------------- /misc/spectral-scan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | # use ath9k Wi-Fi adapter to perform a 2.4 GHz spectral scan 3 | # 4 | # http://blog.altermundi.net/article/playing-with-ath9k-spectral-scan/ 5 | # https://github.com/simonwunderlich/FFT_eval 6 | 7 | phy=phy0 8 | dev=wlan0 9 | 10 | dbg=/sys/kernel/debug/ieee80211/$phy/ath9k 11 | tmp=/tmp/fft_$$ 12 | 13 | if [ $(id -u) -eq 0 ]; then 14 | if ! [ -d "$dbg" ]; then 15 | echo "Missing $dbg, you need CONFIG_ATH9K_DEBUGFS=y" >&2 16 | exit 1 17 | fi 18 | echo 'chanscan' > $dbg/spectral_scan_ctl 19 | iw $dev scan 20 | cat $dbg/spectral_scan0 > "$1" 21 | echo 'disable' > $dbg/spectral_scan_ctl 22 | else 23 | touch "$tmp" 24 | if sudo "$0" "$tmp" > /dev/null; then 25 | (cd ~/src/misc/FFT_eval && ./fft_eval "$tmp") 26 | #(cd ~/src/misc/ath_spectral/UI && 27 | # LD_LIBRARY_PATH=qwt/lib athScan/athScan "$tmp") 28 | fi 29 | fi 30 | -------------------------------------------------------------------------------- /misc/ssh_force_lp.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int setsockopt(int fd, int level, int name, const void *value, socklen_t len) 9 | { 10 | static int (*real_setsockopt)(int, int, int, const void *, socklen_t); 11 | int r; 12 | 13 | if (!real_setsockopt) 14 | real_setsockopt = dlsym(RTLD_NEXT, "setsockopt"); 15 | 16 | if ((level == SOL_IP && name == IP_TOS) || 17 | (level == SOL_IPV6 && name == IPV6_TCLASS)) 18 | { 19 | /* This is probably the TCP socket that will be used for SSH. */ 20 | r = real_setsockopt(fd, SOL_TCP, TCP_CONGESTION, "lp", sizeof "lp"); 21 | if (r != 0) 22 | warn("Could not set congestion control algorithm"); 23 | } 24 | 25 | return real_setsockopt(fd, level, name, value, len); 26 | } 27 | -------------------------------------------------------------------------------- /misc/svn-clone: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # svn-clone - mirror a SVN repository with history using svnsync 3 | 4 | src=$1 5 | dst=$2 6 | 7 | if [ ! "$src" ]; then 8 | echo "Usage: ${0##*/} [dst-dir]" 9 | exit 2 10 | fi 11 | 12 | if [ ! "$dst" ]; then 13 | dst=$src 14 | while case $dst in */) true;; *) false;; esac; do 15 | dst=${dst%/} 16 | done 17 | dst=${dst##*/}.svn 18 | fi 19 | 20 | lib=$(which libfunsync.so 2>/dev/null) 21 | 22 | if [ "$lib" ]; then 23 | export LD_PRELOAD=${LD_PRELOAD}${LD_PRELOAD:+:}$lib 24 | else 25 | echo "Warning: libfunsync not available, sync will be slow" 26 | fi 27 | 28 | echo "Cloning to ${dst}..." 29 | 30 | dsturl=file://$(readlink -f "$dst") 31 | 32 | if [ ! -e "$dst/format" ]; then 33 | echo "Creating empty local repository..." 34 | svnadmin create "$dst" 35 | fi 36 | 37 | if [ ! -e "$dst/hooks/pre-revprop-change" ]; then 38 | echo "Installing pre-revprop-change hook..." 39 | ln -s $(which true) "$dst/hooks/pre-revprop-change" 40 | fi 41 | 42 | if ! grep -qs "^svn:sync-from-url" "$dst/db/revprops/0/0"; then 43 | echo "Initializing svnsync..." 44 | svnsync init "$dsturl" "$src" 45 | 46 | uuid=$(svnlook propget --revprop -r 0 "$dst" "svn:sync-from-uuid") 47 | if [ "$uuid" ]; then 48 | echo "Setting local repository UUID to $uuid..." 49 | svnadmin setuuid "$dst" "$uuid" 50 | fi 51 | fi 52 | 53 | echo "Synchronizing local repository..." 54 | svnsync sync "$dsturl" "$src" 55 | -------------------------------------------------------------------------------- /misc/sysrgba: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | mode=$1 6 | 7 | if [[ ! $mode ]]; then 8 | info "listing current symlinks" 9 | for file in 10-{sub-pixel,sub-pixel-{bgr,rgb,vbgr,vrgb},no-sub-pixel}.conf; do 10 | if [[ -e /etc/fonts/conf.d/$file ]]; then 11 | echo "$file => $(readlink /etc/fonts/conf.d/$file)" 12 | fi 13 | done 14 | exit 15 | fi 16 | 17 | if [[ $mode == @(none|off) ]]; then 18 | mode=no-sub-pixel 19 | info "setting mode to '$mode'" 20 | elif [[ $mode == @(rgb|bgr|vrgb|vbgr) ]]; then 21 | mode=sub-pixel-$mode 22 | info "setting mode to '$mode'" 23 | elif [[ $mode == @(default|reset) ]]; then 24 | mode=default 25 | info "clearing all symlinks" 26 | else 27 | die "invalid mode '$mode'" 28 | fi 29 | 30 | if [[ -d /usr/share/fontconfig/conf.avail ]]; then 31 | dir=/usr/share/fontconfig/conf.avail # Debian 32 | elif [[ -d /etc/fonts/conf.avail ]]; then 33 | dir=.. # Arch 34 | else 35 | die "'conf.avail' directory not found" 36 | fi 37 | 38 | # Remove all other files 39 | sudo rm -vf /etc/fonts/conf.d/10-{sub-pixel-{bgr,rgb,vbgr,vrgb},no-sub-pixel}.conf 40 | 41 | if [[ $mode == default ]]; then 42 | sudo rm -vf /etc/fonts/conf.d/10-sub-pixel.conf 43 | else 44 | sudo ln -vnsf $dir/conf.avail/10-$mode.conf /etc/fonts/conf.d/10-sub-pixel.conf 45 | fi 46 | -------------------------------------------------------------------------------- /misc/tail-conntrack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if (( ! $# )); then 4 | if (( UID != 0 )); then 5 | set -- sudo 6 | fi 7 | elif [[ $1 == @* ]]; then 8 | set -- ssh -l root ${1#@} 9 | fi 10 | 11 | "$@" conntrack -E | sed $' 12 | s/\\[DESTROY\\].*/\e[31m&\e[m/; 13 | s/\\[NEW\\].*/\e[32m&\e[m/; 14 | s/\\[UPDATE\\].*/\e[33m&\e[m/; 15 | s/\\[[A-Z]*\\]/\e[1m&\e[22m/g; 16 | ' 17 | -------------------------------------------------------------------------------- /misc/testrad.md: -------------------------------------------------------------------------------- 1 | _testrad_ looks for preconfigured profiles in `~/.config/nullroute.eu.org/testrad.conf.sh`. The configuration uses Bash script syntax, so a profile looks roughly like this: 2 | 3 | server_example=( 4 | host 192.0.42.1 5 | secret testing123 6 | ) 7 | 8 | profile_example=( 9 | via example 10 | user test@example.com 11 | pass rainbowdash 12 | eap ttls 13 | ) 14 | 15 | profile_example_peap=( 16 | inherit example 17 | eap peap 18 | ) 19 | -------------------------------------------------------------------------------- /misc/tla-clone: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | usage() { 6 | echo "Usage: $progname [-t] [dest-dir]" 7 | echo "" 8 | echo_opt "-t" "Use old 'tla' archive format (default is 'baz')" 9 | } 10 | 11 | arg_format="" 12 | 13 | while getopts ":t" OPT; do 14 | case $OPT in 15 | t) arg_format="--tla";; 16 | *) lib:die_getopts;; 17 | esac 18 | done; shift $((OPTIND-1)) 19 | 20 | src=$1 21 | dest=$2 22 | 23 | if ! [[ "$src" ]]; then 24 | die "missing source URL" 25 | fi 26 | info "source URL: $src" 27 | 28 | name=$(curl -sSf "$src/=meta-info/name") 29 | if ! [[ "$name" ]]; then 30 | die "could not determine source archive name" 31 | fi 32 | info "archive name: $name" 33 | 34 | if ! [[ "$dest" ]]; then 35 | dest="$PWD/$name" 36 | fi 37 | dest=$(readlink -f "$dest") 38 | info "destination: $dest" 39 | 40 | if ! [[ "$(tla whereis-archive "$name-SOURCE")" == "$src" ]]; then 41 | lib:echo "Registering origin archive '$name-SOURCE'" 42 | tla register-archive --force "$name-SOURCE" "$src" 43 | fi 44 | 45 | if ! [[ -d "$dest/=meta-info" ]]; then 46 | lib:echo "Registering local mirror archive '$name'" 47 | tla register-archive --force --delete "$name" 48 | 49 | lib:echo "Mirroring local archive" 50 | tla make-archive $arg_format --mirror-from "$name-SOURCE" "$dest" 51 | fi 52 | 53 | lib:echo "Updating local mirror archive" 54 | tla archive-mirror "$name" 55 | -------------------------------------------------------------------------------- /misc/ubnt-airview: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | ip=$1 6 | 7 | [[ $ip ]] || die "missing IP address" 8 | 9 | exec java-redir -jar ~/.local/lib/airview.jar "ubnt://$ip:18888" 10 | -------------------------------------------------------------------------------- /misc/unhex.c: -------------------------------------------------------------------------------- 1 | /* unhex -- convert data from hexadecimal */ 2 | #define _GNU_SOURCE /* for fmemopen */ 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) { 8 | FILE *input = stdin; 9 | int opt; 10 | 11 | char c = 0, d = 0; 12 | int odd = 0; 13 | 14 | while ((opt = getopt(argc, argv, "a:")) != -1) { 15 | switch (opt) { 16 | case 'a': 17 | input = fmemopen(optarg, strlen(optarg), "r"); 18 | break; 19 | default: 20 | return 2; 21 | } 22 | } 23 | 24 | if (argc > optind) { 25 | fprintf(stderr, "unhex: too many arguments\n"); 26 | return 2; 27 | } 28 | 29 | for (;;) { 30 | c = fgetc(input); 31 | 32 | if (c == EOF) break; 33 | else if (c >= '0' && c <= '9') c -= '0'; 34 | else if (c >= 'a' && c <= 'f') c -= 'a' - 10; 35 | else if (c >= 'A' && c <= 'F') c -= 'A' - 10; 36 | else if (c == 'x' && odd && d == 0) { odd = 0; continue; } 37 | else continue; 38 | 39 | if (odd) 40 | fputc(d | c, stdout); 41 | else 42 | d = c << 4; 43 | 44 | odd = !odd; 45 | } 46 | 47 | if (odd) 48 | fprintf(stderr, "unhex: odd number of input nibbles\n"); 49 | 50 | return odd; 51 | } 52 | -------------------------------------------------------------------------------- /misc/url-file-handler: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | import subprocess 4 | 5 | def parse_file(path): 6 | with open(path, "r") as fh: 7 | for line in fh: 8 | line = line.rstrip() 9 | if line.startswith("URL="): 10 | return line[4:] 11 | elif line.startswith("URL:"): 12 | # Sony-Ericsson vCard syntax 13 | return line[4:] 14 | 15 | def alert(msg): 16 | subprocess.run(["zenity", 17 | "--error", 18 | "--title", "Internet Shortcut – Error", 19 | "--text", msg]) 20 | exit("error: %s" % msg) 21 | 22 | def confirm(url): 23 | msg = f"Do you want to visit this site?\n\n{url}" 24 | r = subprocess.run(["zenity", 25 | "--question", 26 | "--title", "Internet Shortcut", 27 | "--text", msg]) 28 | return (r.returncode == 0) 29 | 30 | def open_url(url): 31 | subprocess.run(["xdg-open", url]) 32 | 33 | parser = argparse.ArgumentParser() 34 | parser.add_argument("file") 35 | args = parser.parse_args() 36 | 37 | url = parse_file(args.file) 38 | if not url: 39 | alert("File %r is not a valid Internet shortcut." % args.file) 40 | if not confirm(url): 41 | exit(1) 42 | open_url(url) 43 | -------------------------------------------------------------------------------- /misc/usbstatus: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # usb-status -- display USB power management status on Linux 3 | 4 | { 5 | printf "%s\t%s\t%s\t%s\t%s\t%s\n" "ID" "DEVICE" "AUTO" "STATUS" "CONTROL" "LEVEL" 6 | for dev in /sys/bus/usb/devices/*; do 7 | if ! test -e $dev/power/autosuspend; then 8 | continue 9 | fi 10 | 11 | vid=$(< $dev/idVendor) 12 | pid=$(< $dev/idProduct) 13 | modalias=usb:v${vid^^}p${pid^^} 14 | 15 | manu=$(systemd-hwdb query $modalias | sed -n 's/^ID_VENDOR_FROM_DATABASE=//p') 16 | if [[ ! $manu ]]; then 17 | if [[ -e $dev/manufacturer ]]; then 18 | manu=$(< $dev/manufacturer) 19 | else 20 | manu="Unknown vendor $vid" 21 | fi 22 | fi 23 | 24 | prod=$(systemd-hwdb query $modalias | sed -n 's/^ID_MODEL_FROM_DATABASE=//p') 25 | if [[ ! $prod ]]; then 26 | if [[ -e $dev/product ]]; then 27 | prod=$(< $dev/product) 28 | else 29 | prod="Unknown product $pid" 30 | fi 31 | fi 32 | 33 | autosusp=$(< $dev/power/autosuspend) 34 | rstat=$(< $dev/power/runtime_status) 35 | control=$(< $dev/power/control) 36 | level=$(< $dev/power/level) 37 | 38 | manu=${manu//"$(uname -sr)"/"$(uname -s)"} 39 | 40 | printf "%s\t%s\t%s\t%s\t%s\t%s\n" "${dev##*/}" "$manu $prod" "$autosusp" "${rstat:0:10}" "$control" "$level" 41 | done 42 | } | column -t -s $'\t' 43 | -------------------------------------------------------------------------------- /misc/util.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "util.h" 3 | #include 4 | #include 5 | #include 6 | 7 | int mkdir_p(const char *path, mode_t mode) { 8 | struct stat st; 9 | const char *p, *e; 10 | int r; 11 | 12 | e = strrchr(path, '/'); 13 | if (!e) 14 | return -EINVAL; 15 | p = strndupa(path, e - path); 16 | 17 | r = stat(p, &st); 18 | if (r == 0 && !S_ISDIR(st.st_mode)) 19 | return -ENOTDIR; 20 | 21 | p = path + strspn(path, "/"); 22 | for (;;) { 23 | char *t; 24 | 25 | e = p + strcspn(p, "/"); 26 | p = e + strspn(e, "/"); 27 | if (!*p) 28 | break; 29 | 30 | t = strndup(path, e - path); 31 | if (!t) 32 | return -ENOMEM; 33 | 34 | r = mkdir(t, mode); 35 | free(t); 36 | if (r < 0 && errno != EEXIST) 37 | return -errno; 38 | } 39 | 40 | r = mkdir(path, mode); 41 | if (r < 0 && errno != EEXIST) 42 | return -errno; 43 | 44 | return 0; 45 | } 46 | 47 | char * shell_escape(const char *str) { 48 | char *output, *ptr; 49 | 50 | output = malloc(strlen(str) * 2 + 3); 51 | 52 | ptr = output; 53 | *ptr++ = '"'; 54 | while (*str) { 55 | switch (*str) { 56 | case '"': 57 | case '$': 58 | case '\\': 59 | case '`': 60 | *ptr++ = '\\'; 61 | default: 62 | *ptr++ = *str++; 63 | } 64 | } 65 | *ptr++ = '"'; 66 | *ptr++ = '\0'; 67 | 68 | return output; 69 | } 70 | -------------------------------------------------------------------------------- /misc/vi6tables: -------------------------------------------------------------------------------- 1 | vitables -------------------------------------------------------------------------------- /misc/vici-get-remote-ip: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # https://raw.githubusercontent.com/strongswan/strongswan/master/src/libcharon/plugins/vici/ruby/lib/vici.rb 3 | require 'socket' 4 | require "#{ENV["HOME"]}/code/thirdparty/vici" 5 | 6 | wanted = ARGV[0] 7 | abort "missing remote-id parameter" if !wanted 8 | 9 | vici = Vici::Connection.new 10 | vici.list_sas do |data| 11 | data.each do |name, sa| 12 | next if sa["state"] != "ESTABLISHED" 13 | next if sa["remote-id"] != wanted 14 | puts sa["remote-host"] 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /misc/vitables: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # vitables -- interactively edit the current iptables ruleset 3 | 4 | . lib.bash || exit 5 | 6 | case ${0##*/} in 7 | vi6tables) 8 | iptables='ip6tables';; 9 | vitables|*) 10 | iptables='iptables';; 11 | esac 12 | 13 | temp=$(mktemp /tmp/vitables.XXXXXXXX) 14 | orig=$(mktemp /tmp/vitables.XXXXXXXX) 15 | 16 | sudo $iptables-save > "$temp" || exit 17 | 18 | if [[ ! -s "$temp" ]]; then 19 | vmsg "No tables found; iptables is probably not in use on this system." >&2 20 | rm -f "$temp" 21 | exit 1 22 | fi 23 | 24 | cp "$temp" "$orig" 25 | 26 | while true; do 27 | ${EDITOR:-vi} "$temp" 28 | if ! grep -qs '^[^#]' "$temp"; then 29 | vmsg "File empty, reload aborted" >&2 30 | break 31 | elif cmp -s "$temp" "$orig"; then 32 | vmsg "No changes made" >&2 33 | break 34 | elif sudo $iptables-restore < "$temp"; then 35 | vmsg "Rules reloaded successfully" 36 | break 37 | elif ! confirm "warning: Failed to load rules; edit again?"; then 38 | exit 39 | break 40 | fi 41 | done 42 | 43 | rm -f "$temp" "$orig" 44 | -------------------------------------------------------------------------------- /misc/weechat-fmtlogs.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # vim: ts=4:sw=4:et 3 | 4 | sub fmt { 5 | my ($str, $color) = @_; 6 | if ($color) { "\e[38;5;".$color."m".$str."\e[m"; } else { $str; } 7 | } 8 | 9 | while (<>) { 10 | my ($f_time, $f_prefix, $f_msg) = split(/\t/, $_, 3); 11 | 12 | my $c_prefix = 76; 13 | my $c_msg = 0; 14 | 15 | if ($f_prefix eq " *") { 16 | $c_prefix = 196; 17 | $c_msg = 208; 18 | } 19 | elsif ($f_prefix !~ /[A-Za-z0-9_]/ || $f_prefix eq "-i-") { 20 | $c_msg = 66; 21 | } 22 | 23 | print fmt($f_time, 239), " ", 24 | fmt($f_prefix, $c_prefix), " ", 25 | fmt($f_msg, $c_msg); 26 | } 27 | -------------------------------------------------------------------------------- /misc/wget-raw-archive.org: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # wget-raw-archive.org - download raw archive.org pages bypassing robots 3 | args=() 4 | for arg; do 5 | if [[ $arg == 'http://'* || $arg == 'https://'* ]]; then 6 | arg=${arg/'/http:/'/'id_/http:/'} 7 | fi 8 | args+=("$arg") 9 | done 10 | #exec wget -e robots=off "${args[@]}" 11 | for arg in "${args[@]}"; do 12 | #curl -L -O "$arg" 13 | file=${arg##*/} 14 | file=${file:-index.html} 15 | wget "$arg" -O "$file" 16 | done 17 | -------------------------------------------------------------------------------- /misc/wigle2kml.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | BEGIN { 4 | FS = ","; 5 | print ""; 6 | print ""; 7 | print ""; 8 | } 9 | 10 | NR > 2 {} 11 | 12 | #$2 ~ /^utena/ { 13 | $1 ~ /^..:..:..:..:..:..$/ { 14 | print " "; 15 | print " "" $2 "" (" $6 ", " $1 ")"; 16 | print " "; 17 | print " " $8 "," $7 "," $9 ""; 18 | print " "; 19 | print " "; 20 | } 21 | 22 | END { 23 | print ""; 24 | print ""; 25 | } 26 | -------------------------------------------------------------------------------- /misc/windows/dotnet.cmd: -------------------------------------------------------------------------------- 1 | :: Locate and start the latest version of Microsoft .NET C# Compiler 2 | @setlocal 3 | @set framework=Framework64 4 | @if "%PROCESSOR_ARCHITECTURE%"=="x86" set framework=Framework 5 | @for /d %%d in ("%SystemRoot%\Microsoft.NET\%framework%\v*.*") do @( 6 | set version=%%~nxd 7 | set dir=%%~d 8 | ) 9 | @echo Using .NET %framework% %version% 10 | @set PATH=%dir%;%PATH% 11 | @%* 12 | -------------------------------------------------------------------------------- /misc/windows/hacks/update-env-vars.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | :main 3 | set __append_path=n 4 | for /f "usebackq tokens=1,2,* delims= " %%a in (`reg query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment"`) do call :process "%%~a" "%%~b" "%%~c" 5 | set __append_path=y 6 | for /f "usebackq tokens=1,2,* delims= " %%a in (`reg query HKCU\Environment`) do call :process "%%~a" "%%~b" "%%~c" 7 | set __append_path= 8 | goto :eof 9 | 10 | :process 11 | set "__var_name=%~1" 12 | if not "%__var_name:~0,4%"==" " goto :eof 13 | set "__var_name=%__var_name:~4%" 14 | :: It is not necessary to skip %PROMPT% -- I just want 15 | :: to avoid certain kinds of confusion that may result. 16 | if /i "%__var_name%"=="PROMPT" goto :process_next 17 | if /i "%__var_name%"=="PATH" ( 18 | if "%__append_path%"=="y" ( 19 | set "%__var_name%=%PATH%;%~3" 20 | goto :process_next 21 | ) 22 | ) 23 | set "%__var_name%=%~3" 24 | 25 | :process_next 26 | set __var_name= 27 | goto :eof 28 | -------------------------------------------------------------------------------- /misc/windows/identd/win32-identd.md: -------------------------------------------------------------------------------- 1 | # Ident (RFC 1413) service for Windows NT 2 | 3 | ## Features 4 | 5 | * IPv6 6 | * Multi-user support 7 | 8 | ## Requirements 9 | 10 | * [PyWin32](http://starship.python.net/crew/mhammond/win32/Downloads.html) 11 | * Windows XP or later 12 | 13 | ## Installation 14 | 15 | win32-identd.py --startup auto install 16 | win32-identd.py start 17 | 18 | The service will automatically listen on `0.0.0.0` and `::` port 113. 19 | 20 | Requests are logged to Event Log. 21 | 22 | ## Bugs 23 | 24 | * I should probably rewrite it using `asyncore`. 25 | -------------------------------------------------------------------------------- /misc/windows/make.cmd: -------------------------------------------------------------------------------- 1 | @setlocal & prompt $g 2 | @if not "%~1"=="" goto :%~1 || goto :eof 3 | 4 | :monoff 5 | call dotnet csc /t:winexe /o /r:System.dll /r:System.Windows.Forms.dll /out:"%SystemRoot%\monoff.scr" monoff.cs 6 | goto :eof 7 | -------------------------------------------------------------------------------- /misc/windows/powermonitor/.gitignore: -------------------------------------------------------------------------------- 1 | actions.py 2 | -------------------------------------------------------------------------------- /misc/windows/powermonitor/README.md: -------------------------------------------------------------------------------- 1 | # Power event monitor service 2 | 3 | ## Requirements 4 | 5 | * [PyWin32](http://starship.python.net/crew/mhammond/win32/Downloads.html) 6 | 7 | ## Installation: 8 | 9 | 1. Copy `actions.py.example` to `actions.py` and edit according to your needs. 10 | 11 | 2. Install and start the service: 12 | 13 | powermonitor.py --startup auto install 14 | powermonitor.py start 15 | 16 | The `actions.py` file will be reloaded every time. 17 | -------------------------------------------------------------------------------- /misc/windows/powermonitor/actions.py.example: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | def Suspend(): 4 | pass 5 | 6 | def Resume(): 7 | pass 8 | -------------------------------------------------------------------------------- /misc/wtmp_filter: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Clean out proftpd clutter out of /var/log/wtmp 3 | import argparse 4 | import ctypes 5 | import re 6 | 7 | from nullroute.system.utmp import UtType, struct_utent 8 | 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("--skip-user", metavar="REGEX", 11 | help="ignore entries where .user fully matches regex") 12 | parser.add_argument("--skip-line", metavar="REGEX", 13 | help="ignore entries where .line fully matches regex") 14 | parser.add_argument("input") 15 | parser.add_argument("output") 16 | args = parser.parse_args() 17 | 18 | sz = ctypes.sizeof(struct_utent) 19 | 20 | with open(args.input, "rb") as ifh: 21 | with open(args.output, "wb") as ofh: 22 | while buf := ifh.read(sz): 23 | en = struct_utent.from_buffer_copy(buf) 24 | if args.skip_user and re.fullmatch(args.skip_user, en.ut_user.decode()): 25 | print("SKIP:", en) 26 | continue 27 | if args.skip_line and re.fullmatch(args.skip_line, en.ut_line.decode()): 28 | print("SKIP:", en) 29 | continue 30 | print("pass:", en) 31 | ofh.write(buf) 32 | -------------------------------------------------------------------------------- /misc/xterm-color-chooser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grawity/code/f256febd681d54b3f982e2dbb561c0fdb968d8b3/misc/xterm-color-chooser.png -------------------------------------------------------------------------------- /misc/zipdate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | do_rename=0 6 | 7 | if [[ $1 == "-m" ]]; then 8 | do_rename=1 9 | shift 10 | fi 11 | 12 | file=$1 13 | 14 | [[ -f "$file" ]] || die "'$file' is not a regular file" 15 | [[ "$file" == *.zip ]] || die "'$file' is not a Zip archive" 16 | 17 | date=$(unzip -l "$file" | grep -v '/$' | awk '/^ / && $2 ~ /^2/ {print $2}' | sort | tail -1) 18 | 19 | if (( do_rename )); then 20 | new=$file 21 | new=${new%.zip} 22 | new=${new%_????-??-??} 23 | new=${new}_${date}.zip 24 | if [[ "$file" != "$new" ]]; then 25 | mv -vi "$file" "$new" 26 | else 27 | echo "${file%%*/}: no change" 28 | fi 29 | else 30 | echo "$date" 31 | fi 32 | -------------------------------------------------------------------------------- /misc/ziphash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | full=1 4 | 5 | if (( full )); then 6 | for file; do 7 | hash=$(zipinfo -v "$file" | grep -v '^Archive:' | sha1sum | awk '{print $1}') 8 | echo "$hash $file" 9 | done 10 | else 11 | for file; do 12 | hash=$(zipinfo -v "$file" | grep "32-bit CRC value" | grep -v 00000000 | sort | sha1sum | awk '{print $1}') 13 | echo "$hash $file" 14 | done 15 | fi 16 | -------------------------------------------------------------------------------- /mksrcinfo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # mksrcinfo -- compatibility wrapper 3 | 4 | . lib.bash || exit 5 | 6 | if [ ! -s PKGBUILD ]; then 7 | vdie "no PKGBUILD" 8 | fi 9 | 10 | makepkg --printsrcinfo > .SRCINFO 11 | -------------------------------------------------------------------------------- /myip: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # myip -- use online services to determine external IPv4 address 3 | 4 | . lib.bash || exit 5 | 6 | usage() { 7 | echo "Usage: $progname [-46]" 8 | } 9 | 10 | afs='-4 -6' 11 | 12 | while getopts :46 OPT; do 13 | case $OPT in 14 | 4) afs="-4";; 15 | 6) afs="-6";; 16 | *) lib:die_getopts;; 17 | esac 18 | done; shift $[OPTIND-1] 19 | 20 | found=0 21 | 22 | for af in $afs; do 23 | case $af in 24 | -4) type=A; res=208.67.222.222;; 25 | -6) type=AAAA res=2620:119:35::35;; 26 | esac 27 | 28 | if ip $af route get $res &>/dev/null; then 29 | dig $af +short myip.opendns.com. $type @resolver1.opendns.com. || 30 | curl $af -Ssf http://whatismyip.akamai.com && 31 | found=1 32 | fi 33 | done 34 | 35 | (( found )) 36 | -------------------------------------------------------------------------------- /obj/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grawity/code/f256febd681d54b3f982e2dbb561c0fdb968d8b3/obj/.empty -------------------------------------------------------------------------------- /onchange: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # onchange -- run a command whenever a file is changed 3 | 4 | . lib.bash || exit 5 | 6 | usage() { 7 | echo "Usage: $progname ... -- " 8 | } 9 | 10 | paths=() 11 | cmd=() 12 | 13 | while getopts : OPT; do 14 | case $OPT in 15 | *) lib:die_getopts;; 16 | esac 17 | done; shift $((OPTIND-1)) 18 | 19 | argstate=0 20 | for arg; do 21 | if (( argstate == 0 )); then 22 | if [[ $arg == -- ]]; then 23 | argstate=1 24 | else 25 | paths+=("$arg") 26 | fi 27 | else 28 | cmd+=("$arg") 29 | fi 30 | done 31 | 32 | if (( ! ${#paths[@]} )); then 33 | vdie "No files specified" 34 | fi 35 | 36 | if (( ! ${#cmd[@]} )); then 37 | cmd=(make) 38 | elif (( ${#cmd[@]} == 1 )) && [[ $cmd = *\ * ]]; then 39 | cmd=(sh -c "$cmd") 40 | fi 41 | 42 | vmsg "Will monitor ${#paths[@]} files and run ${cmd[*]@Q}" 43 | 44 | inotifywait -q -m -e close_write -- "${paths[@]}" | 45 | while read -r ev; do 46 | echo "Event: $ev" 47 | "${cmd[@]}" || warn "Command failed with status $?" 48 | done 49 | -------------------------------------------------------------------------------- /osguess: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # osguess -- show distribution-specific information 3 | 4 | have() { command -v "$1" &>/dev/null; } 5 | 6 | unset dist 7 | 8 | if [[ -e /etc/os-release ]]; then 9 | dist=$(. /etc/os-release && echo "$ID $ID_LIKE") 10 | fi 11 | if [[ ! $dist ]]; then 12 | dist=$(uname) 13 | fi 14 | xdist=:${dist// /:}: 15 | 16 | for arg in "$@"; do 17 | case $arg in 18 | dist) 19 | echo "$dist" 20 | ;; 21 | package-mgr) 22 | case $xdist in 23 | *:alpine:*) 24 | echo apk;; 25 | *:arch:*) 26 | echo pacman;; 27 | *:debian:*) 28 | echo dpkg;; 29 | *) 30 | echo "${0##*/}: unknown distribution '$dist'" >&2 31 | exit 1 32 | esac 33 | ;; 34 | *) 35 | echo "${0##*/}: unknown argument '$arg'" >&2 36 | exit 2 37 | esac 38 | done 39 | -------------------------------------------------------------------------------- /psel: -------------------------------------------------------------------------------- 1 | pclip -------------------------------------------------------------------------------- /puts: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # puts -- print arguments after processing C-like escapes 3 | 4 | for arg; do 5 | unescape -a "$arg" 6 | done 7 | -------------------------------------------------------------------------------- /rfc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # rfc -- open an IETF RFC 3 | 4 | . lib.bash || exit 5 | 6 | if (( ! $# )); then 7 | vdie "no document specified" 8 | fi 9 | 10 | dir=/usr/share/doc/rfc/txt 11 | args=() 12 | for arg; do 13 | args+=($dir/rfc$arg.txt) 14 | done 15 | cd $dir && vim -p "${args[@]}" 16 | -------------------------------------------------------------------------------- /rlisthosts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # rlisthosts -- helper for rdo/rup to discover hosts 3 | # 4 | # Might use LDAP one day, but for now it's just a static list (instead of 5 | # having that list hardcoded in rup, then copied to other tools). 6 | 7 | import argparse 8 | 9 | base_hosts = ["wolke", "sky", "star", "land", "ember", "wind"] 10 | other_hosts = ["vm-vol5", "vm-litnet"] 11 | 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument("-a", action="store_true", 14 | help="include primary containers") 15 | parser.add_argument("host", nargs="*") 16 | args = parser.parse_args() 17 | 18 | hosts = base_hosts[:] 19 | if args.a: 20 | hosts += other_hosts[:] 21 | 22 | if args.host: 23 | arg_hosts = " ".join(args.host).replace(",", " ") 24 | if arg_hosts.startswith("+"): 25 | hosts += arg_hosts[1:].split() 26 | else: 27 | hosts = arg_hosts.split() 28 | 29 | print(*hosts) 30 | -------------------------------------------------------------------------------- /rlocate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . lib.bash || exit 4 | 5 | usage() { 6 | echo "Usage: $progname [-H hosts] [-bw] ..." 7 | echo 8 | echo_opt "-H hosts" "list of hosts to search" 9 | echo_opt "-b" "match against file name only" 10 | echo_opt "-w" "match against entire path" 11 | } 12 | 13 | hosts="+myth" 14 | args="" 15 | 16 | while getopts ":H:bw" OPT; do 17 | case $OPT in 18 | H) hosts=${OPTARG//,/ };; 19 | b) args+=" -$OPT";; 20 | w) args+=" -$OPT";; 21 | *) lib:die_getopts;; 22 | esac 23 | done; shift $((OPTIND-1)) 24 | 25 | hosts=`rlisthosts "$hosts"` || exit 26 | 27 | if (( ! $# )); then 28 | vdie "query not specified" 29 | fi 30 | 31 | for arg; do 32 | args+=" ${arg@Q}" 33 | done 34 | 35 | rdo -q -H "$hosts" "bin/loc $args | sed \"s,^,/net/\$(hostname),\"" 36 | -------------------------------------------------------------------------------- /rmtodo: -------------------------------------------------------------------------------- 1 | todo -------------------------------------------------------------------------------- /rpw: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # rpw -- generate a random password 3 | 4 | . lib.bash || exit 5 | 6 | usage() { 7 | echo "Usage: ${0##*/} [-c] [-l] []" 8 | echo "" 9 | echo "Generates a random password." 10 | echo "" 11 | echo " -c copy password to clipboard" 12 | echo " -l use only lowercase characters" 13 | echo "" 14 | echo "If length is negative, characters will be in dash-separated groups." 15 | } 16 | 17 | length=-20 18 | dash=0 19 | lcase=0 20 | clip=0 21 | 22 | for arg; do 23 | case $arg in 24 | --help) usage; exit;; 25 | -c) clip=1;; 26 | -l) lcase=1;; 27 | -[0-9]*) length=$arg;; 28 | [0-9]*) length=$arg;; 29 | *) vdie "bad argument '$arg'";; 30 | esac 31 | done 32 | 33 | if (( length < 0 )); then 34 | dash=1 35 | length=$(( -length )) 36 | fi 37 | 38 | pw=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c "$length") 39 | 40 | if (( lcase )); then 41 | pw=${pw,,} 42 | fi 43 | 44 | if (( dash )); then 45 | pw=$(printf '%s\n' "$pw" | sed -r 's/.{5}/&-/g; s/-$//') 46 | fi 47 | 48 | if (( clip )); then 49 | printf '%s' "$pw" | gclip 50 | fi 51 | 52 | printf '%s\n' "$pw" 53 | -------------------------------------------------------------------------------- /shoreplug: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # shoreplug -- remotely power-cycle Shore's smart power socket 3 | export TAPO_USER=$(ad gp =Tapo :email) 4 | export TAPO_PASS=$(ad gp =Tapo !pass) 5 | tapo ${0##*/}.sym "$@" 6 | -------------------------------------------------------------------------------- /showcolors: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # showcolors -- Display the 16 basic terminal colors. 3 | 4 | for y in 30 90; do 5 | (( y == 30 )) || printf "\n" 6 | for x in {0..7}; do 7 | fx=$[y+x] 8 | bx=$[10+y+x] 9 | printf "%-9s" "Color $fx:" 10 | printf " \e[2;%dm%s\e[m" $fx "Dimmed" 11 | printf " \e[%dm%s\e[m" $fx "Normal" 12 | printf " \e[1;%dm%s\e[m" $fx "Strong" 13 | printf " " 14 | printf " \e[%dm%s\e[m" $bx " Normal " 15 | printf " \e[1;%dm%s\e[m" $bx " Strong " 16 | printf " " 17 | printf " \e[30;%dm%s\e[m" $bx " Normal " 18 | printf " \e[1;30;%dm%s\e[m" $bx " Strong " 19 | printf "\n" 20 | done 21 | done 22 | -------------------------------------------------------------------------------- /showfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # showfile -- reveal specified items in a file manager window 3 | import argparse 4 | import dbus 5 | import os 6 | import urllib.parse 7 | 8 | def path_to_url(path): 9 | return "file://" + urllib.parse.quote(os.path.abspath(path)) 10 | 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument("path", nargs="+", 13 | help="file to reveal") 14 | args = parser.parse_args() 15 | 16 | for f in args.path: 17 | if not os.path.exists(f): 18 | exit("error: Path %r does not exist" % f) 19 | 20 | fm = dbus.SessionBus().get_object("org.freedesktop.FileManager1", 21 | "/org/freedesktop/FileManager1") 22 | 23 | fm = dbus.Interface(fm, "org.freedesktop.FileManager1") 24 | 25 | fm.ShowItems([path_to_url(p) for p in args.path], "") 26 | -------------------------------------------------------------------------------- /spawn: -------------------------------------------------------------------------------- 1 | .hostrun -------------------------------------------------------------------------------- /srv: -------------------------------------------------------------------------------- 1 | rdt -------------------------------------------------------------------------------- /swapusage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # swapusage -- show current swap usage for all running processes 3 | # 4 | # A port of shell-based `swapusage` tool by Erik Ljungstrom, Mikko 5 | # Rantalainen, and Marc Methot. 6 | import argparse 7 | import glob 8 | import os 9 | 10 | parser = argparse.ArgumentParser() 11 | args = parser.parse_args() 12 | 13 | usage = [] 14 | for dir in glob.glob("/proc/[0-9]*/"): 15 | pid = os.path.basename(dir.rstrip("/")) 16 | with open("%s/comm" % dir, "r") as fh: 17 | name = fh.read().strip() 18 | swap = 0 19 | with open("%s/status" % dir, "r") as fh: 20 | for line in fh: 21 | if line.startswith("VmSwap"): 22 | swap += int(line.split()[1]) 23 | if swap > 0: 24 | usage += [(swap, name, pid)] 25 | usage.sort() 26 | 27 | fmt = "%9s kB %s" 28 | total = 0 29 | for swap, name, pid in usage: 30 | print(fmt % (swap, "%s (%s)" % (name, pid))) 31 | total += swap 32 | print(fmt % (total, "TOTAL")) 33 | -------------------------------------------------------------------------------- /sx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # sx -- start X11 3 | 4 | . lib.bash || exit 5 | 6 | fdisplay() { 7 | local i=0 8 | while [ -e /tmp/.X$i-lock ] || [ -e /tmp/.X11-unix/X$i ]; do 9 | let i++ 10 | done 11 | echo ":$i" 12 | } 13 | 14 | if [ "$DISPLAY" ]; then 15 | vdie "already have an X display" 16 | fi 17 | 18 | if ! vt="vt$(fgconsole)"; then 19 | vdie "could not determine current virtual terminal" 20 | fi 21 | 22 | cd ~ 23 | unset SHLVL 24 | export DISPLAY=$(fdisplay) 25 | 26 | # Prevent an xauth message about absent file 27 | touch "${XAUTHORITY:-"$HOME/.Xauthority"}" 28 | 29 | # Add cookie for current display if missing 30 | cookie=$(xauth -n list "$DISPLAY" | awk '{print $3}') 31 | if ! test "$cookie"; then 32 | cookie=$(mcookie) 33 | xauth -q add "$DISPLAY" . "$cookie" 34 | fi 35 | 36 | # The Xserver accepts any cookie it finds in the file, so it 37 | # must be given only the specific one for this display. 38 | serverauth=$(mktemp /tmp/serverauth.XXXXXXXX) || exit 39 | xauth -f "$serverauth" add :0 . "$cookie" 40 | 41 | xinit "$@" -- "$DISPLAY" "$vt" \ 42 | -keeptty -noreset -background none -quiet \ 43 | -auth "$serverauth" -listen tcp < /dev/null; r=$? 44 | 45 | rm -f "$serverauth" 46 | exit $r 47 | -------------------------------------------------------------------------------- /sysup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # sysup -- upgrade all installed packages 3 | 4 | . lib.bash || exit 5 | 6 | ~/bin/settitle -w "$(hostname)" 7 | 8 | tool=$(osguess package-mgr) || exit 9 | 10 | case $tool in 11 | dpkg) 12 | if [[ -x /usr/bin/apt ]]; then 13 | sudo: nice apt update && 14 | sudo: nice apt full-upgrade -V "$@" 15 | else 16 | sudo: nice apt-get update && 17 | sudo: nice apt-get dist-upgrade -V "$@" 18 | fi 19 | ;; 20 | pacman) 21 | if pgrep -u "$UID" -x firefox &> /dev/null; then 22 | set -- --ignore=firefox "$@" 23 | fi 24 | sudo: nice pacman -Syu "$@" && 25 | if pkgs=$(pacman -Qqdt | grep ^haskell-); then 26 | sudo: nice pacman -Rns $pkgs 27 | fi 28 | ;; 29 | rpm) 30 | sudo: nice yum update "$@" 31 | ;; 32 | *) 33 | echo "${0##*/}: unknown distribution" >&2 34 | exit 1 35 | ;; 36 | esac 37 | -------------------------------------------------------------------------------- /telnet: -------------------------------------------------------------------------------- 1 | htelnet -------------------------------------------------------------------------------- /thirdparty/desupout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grawity/code/f256febd681d54b3f982e2dbb561c0fdb968d8b3/thirdparty/desupout -------------------------------------------------------------------------------- /thirdparty/desupout.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # paul@unsup.sbrk.co.uk 3 | use Compress::Zlib; 4 | use strict; 5 | 6 | my $inf = shift; 7 | my $in; 8 | open(F, "<$inf") || die "Usage: unsup.pl /path/to/supout.inf"; 9 | while () { 10 | $_ =~ s/\s+$//; # strip terminating \r \n or other whitespace chars 11 | if ($_ eq "--BEGIN ROUTEROS SUPOUT SECTION") { 12 | $in = ""; 13 | } elsif ($_ eq "--END ROUTEROS SUPOUT SECTION") { 14 | decode($in); 15 | } else { 16 | $in .= $_; 17 | } 18 | } 19 | 20 | # this is base64 but done in a different byte order 21 | sub decode { 22 | my $in = shift; 23 | # terminating "=" is so that index %64 == 0 for pad char 24 | my $b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 25 | #my $np = length($in)-index($in,"="); # ignored at the moment 26 | #$np = 0 if (-1 == index($in,"=")); 27 | my $out; 28 | for (my $i = 0; $i < length($in); $i+=4) { 29 | my $o = index($b64, substr($in,$i+3,1))%64 << 18 | 30 | index($b64, substr($in,$i+2,1))%64 << 12 | 31 | index($b64, substr($in,$i+1,1))%64 << 6 | 32 | index($b64, substr($in,$i,1))%64; 33 | $out .= chr($o%256); 34 | $out .= chr(($o>>8) % 256); 35 | $out .= chr(($o>>16) % 256); 36 | } 37 | # decoded data consists of "section_name\0zlib_compressed_data" 38 | my $sec = substr($out, 0, index($out,"\0")); 39 | print "==SECTION $sec\n"; 40 | my $cmp = substr($out, index($out,"\0")+1); 41 | my $uncomp = uncompress($cmp); 42 | print "$uncomp\n"; 43 | } 44 | -------------------------------------------------------------------------------- /thirdparty/dnssec-dsfromdns: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # $Cambridge: hermes/conf/bind/bin/dnssec-dsfromdns,v 1.1 2011/05/06 11:36:09 fanf2 Exp $ 3 | eval zone=\$$# 4 | dig +crypto dnskey $zone | dnssec-dsfromkey -f /dev/stdin "$@" 5 | -------------------------------------------------------------------------------- /thirdparty/strnatcmp.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-file-style: "k&r" -*- 2 | 3 | strnatcmp.c -- Perform 'natural order' comparisons of strings in C. 4 | Copyright (C) 2000, 2004 by Martin Pool 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 3. This notice may not be removed or altered from any source distribution. 21 | */ 22 | 23 | 24 | /* CUSTOMIZATION SECTION 25 | * 26 | * You can change this typedef, but must then also change the inline 27 | * functions in strnatcmp.c */ 28 | typedef char nat_char; 29 | 30 | int strnatcmp(nat_char const *a, nat_char const *b); 31 | int strnatcasecmp(nat_char const *a, nat_char const *b); 32 | -------------------------------------------------------------------------------- /thirdparty/writevt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mostly ripped off of console-tools' writevt.c 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char **argv) { 14 | const char sysctl[] = "/proc/sys/dev/tty/legacy_tiocsti"; 15 | char *term = NULL; 16 | char *text = NULL; 17 | int fd; 18 | 19 | if (argc != 3) { 20 | printf("Usage: %s ttydev text\n", "writevt"); 21 | return 2; 22 | } 23 | 24 | term = argv[1]; 25 | text = argv[2]; 26 | 27 | fd = open(sysctl, O_WRONLY); 28 | if (fd >= 0) { 29 | if (write(fd, "1", sizeof "1") < 0) { 30 | err(1, "could not write to %s", sysctl); 31 | } 32 | close(fd); 33 | } else if (errno == ENOENT) { 34 | // ignore; pre-6.2 kernel always had TIOCSTI enabled 35 | } else { 36 | err(1, "could not open %s", sysctl); 37 | } 38 | 39 | fd = open(term, O_RDONLY); 40 | if (fd >= 0) { 41 | while (*text) { 42 | if (ioctl(fd, TIOCSTI, text)) { 43 | err(1, "ioctl(TIOCSTI) failed"); 44 | } 45 | text++; 46 | } 47 | close(fd); 48 | } else { 49 | err(1, "could not open %s", term); 50 | } 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /utfvis: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # utfvis -- make non-ASCII Unicode characters highly visible 3 | 4 | use warnings; 5 | use strict; 6 | use open qw(:std :encoding(UTF-8)); 7 | use Getopt::Long qw(:config bundling no_ignore_case); 8 | 9 | sub usage { 10 | print for 11 | "Usage: utfvis [-o] ...\n", 12 | "\n", 13 | "Options:\n", 14 | " -o, --only show only lines containing non-ASCII characters\n"; 15 | } 16 | 17 | sub hilight { 18 | my ($char, $color) = @_; 19 | $char = sprintf "", ord($char); 20 | if ($color) { 21 | return "\e[1;37;41m$char\e[m"; 22 | } else { 23 | return $char; 24 | } 25 | } 26 | 27 | my $opt_only = 0; 28 | my $opt_color = (-t 1); 29 | 30 | GetOptions( 31 | "o|only!" => \$opt_only, 32 | "color!" => \$opt_color, 33 | "help" => sub { usage(); exit(0); }, 34 | ) or exit(2); 35 | 36 | while (<>) { 37 | my $n = s/[^\n\t\x20-\x7e]/hilight($&, $opt_color)/ge; 38 | if ($opt_only) { 39 | if ($opt_color) { 40 | print "\e[4m$ARGV:$.:\e[m$_" if $n; 41 | } else { 42 | print "$ARGV:$.:$_" if $n; 43 | } 44 | } else { 45 | print; 46 | } 47 | } continue { 48 | # Reset $. between files, as <> doesn't do that automatically. 49 | close ARGV if eof(ARGV); 50 | } 51 | -------------------------------------------------------------------------------- /vim: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ -x /usr/bin/nvim ]; then 3 | exec /usr/bin/nvim "$@" 4 | else 5 | echo "$0: nvim not found" >&2 6 | exec /usr/bin/vim "$@" 7 | fi 8 | -------------------------------------------------------------------------------- /vimdiff: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ -x /usr/bin/nvim ]; then 3 | exec /usr/bin/nvim -d "$@" 4 | else 5 | echo "$0: nvim not found" >&2 6 | exec /usr/bin/vimdiff "$@" 7 | fi 8 | -------------------------------------------------------------------------------- /vis: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # utfvis -- make non-ASCII Unicode characters highly visible 3 | 4 | use warnings; 5 | use strict; 6 | use Getopt::Long qw(:config bundling no_ignore_case); 7 | 8 | sub usage { 9 | print for 10 | "Usage: utfvis [-o] ...\n", 11 | "\n", 12 | "Options:\n", 13 | " -o, --only show only lines containing non-ASCII characters\n"; 14 | } 15 | 16 | sub hilight { 17 | my ($char, $color) = @_; 18 | $char = sprintf "<%02X>", ord($char); 19 | if ($color) { 20 | return "\e[1;37;41m$char\e[m"; 21 | } else { 22 | return $char; 23 | } 24 | } 25 | 26 | my $opt_only = 0; 27 | my $opt_color = (-t 1); 28 | 29 | GetOptions( 30 | "o|only!" => \$opt_only, 31 | "color!" => \$opt_color, 32 | "help" => sub { usage(); exit(0); }, 33 | ) or exit(2); 34 | 35 | while (<>) { 36 | my $n = s/[^\n\t\x20-\x7e]/hilight($&, $opt_color)/ge; 37 | if ($opt_only) { 38 | if ($opt_color) { 39 | print "\e[4m$ARGV:$.:\e[m$_" if $n; 40 | } else { 41 | print "$ARGV:$.:$_" if $n; 42 | } 43 | } else { 44 | print; 45 | } 46 | } continue { 47 | # Reset $. between files, as <> doesn't do that automatically. 48 | close ARGV if eof(ARGV); 49 | } 50 | -------------------------------------------------------------------------------- /vitodo: -------------------------------------------------------------------------------- 1 | todo -------------------------------------------------------------------------------- /whois4: -------------------------------------------------------------------------------- 1 | whois6 -------------------------------------------------------------------------------- /whois6: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # whois4, whois6 -- make Whois queries for a domain's IP addresses 3 | 4 | . lib.bash || exit 5 | 6 | case ${0##*/} in 7 | whois4) af="-4" afname="IPv4";; 8 | whois6) af="-6" afname="IPv6";; 9 | *) vdie "bad invocation";; 10 | esac 11 | 12 | if (( $# < 1 )); then 13 | vdie "missing hostname" 14 | fi 15 | 16 | if (( $# > 1 )); then 17 | vdie "excess arguments" 18 | fi 19 | 20 | if ! have name2addr; then 21 | vdie "ndisc6 not installed" 22 | fi 23 | 24 | if addr=$(name2addr $af "$1") && [[ $addr ]]; then 25 | vmsg "looking up $addr" 26 | whois "$addr" 27 | else 28 | vdie "no $afname address for '$1'" 29 | fi 30 | -------------------------------------------------------------------------------- /wormhole: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | uvx --quiet --from=magic-wormhole wormhole "$@" 3 | -------------------------------------------------------------------------------- /xcat: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # xcat -- like `cat` but with tail-style headings 3 | 4 | if (( ! $# )); then 5 | echo "Usage: ${0##*/} " >&2 6 | exit 2 7 | fi 8 | 9 | if [[ -t 1 ]]; then 10 | header='\e[38;5;12m==> %s <==\e[m\n' 11 | else 12 | header='==> %s <==\n' 13 | fi 14 | 15 | if [[ ${0%%*/} == *tail ]]; then 16 | lines=10 17 | if [[ $1 == -n ]]; then 18 | lines=${1#-n}; shift 19 | if [[ ! $lines ]]; then 20 | lines=$2; shift 21 | fi 22 | fi 23 | for arg; do 24 | printf "$header" "$arg" 25 | tail -n "$lines" "$arg" 26 | printf '\n' 27 | done 28 | else 29 | for arg; do 30 | printf "$header" "$arg" 31 | cat "$arg" 32 | printf '\n' 33 | done 34 | fi 35 | -------------------------------------------------------------------------------- /xtail: -------------------------------------------------------------------------------- 1 | xcat --------------------------------------------------------------------------------