Kategorie: coding

aerotools Update

Dank der Semesterferien fand ich nun endlich Zeit, mein aerotools-Projekt auf Vordermann zu bringen. Neben einigen Bugfixes und Vereinfachungen am Daemon habe ich die Library auf libusb-1.0 portiert, was laut Homepage die empfohlene, aktuelle Version ist. Unter Arch coexistiert sie als libusb1 neben der libusb, die standardmäßig installiert wird – etwas verwirrend, wenn man den Hinweistext auf der Homepage nicht gelesen hat ;)

Alle aquaero®-Besitzer seien also herzlich eingeladen, die neue Version zu testen! Bugreports sind immer willkommen, am Besten über die “Issues”-Funktion auf Github.

logcheck-rules prüfen

Beim Ändern von ignore-Regelsätzen für logcheck unterlaufen mir ganz gern Tippfehler in komplexeren Ausdrücken. Dumm nur, wenn ich das erst beim nächsten Cron-Run merke, in Form einer solchen Meldung:

egrep: Unmatched ) or \)

Toll: weder Regelsatz noch Zeilennummer werden genannt, also manuell suchen. Da es sich aber meist um umfangreiche Regelsätze handelt und ich (selbst bei gefundenem Satz) keine Möglichkeit gefunden habe, egrep die Zeilennummer des ungültigen Ausdrucks zu entlocken, entstand auf die Schnelle folgendes simples Script:

#!/bin/bash
 
if [ $# -ne 1 ]; then
    echo "usage: $0 RULES_FILE"
    exit 1
fi
 
if ! [ -r "$1" ]; then
    echo "unable to read $1"
    exit 1
fi
 
LINES=$(wc -l "$1" | cut -d ' ' -f 1)
 
for I in $(seq $LINES); do
    echo "line $I..."
    echo "foo" | egrep "$(cat "$1" | head -n $I | tail -n 1)"
done
 
exit 0

Es gibt bestimmt auch irgendeine elegantere Lösung, aber vielleicht erspart es ja jemandem die nervige Sucherei :)

Java Gridbags

Dieser animierte Blogpost beschreibt meinen Abend perfekt :)

Arch ramdisk-script 1.4

In meinem Arch Ramdisk-Script <1.4 hatte sich ein dämlicher Bug eingeschlichen: bei sämtlichen rsync-Aufrufen fehlte das --delete.

Das bewirkt z.B. bei Verwendung mit Firefox, dass der Cache nie geleert wird und (streng) monoton wächst – unschön.

Hier die gefixte Version :)

#!/bin/sh
 
#
# Manages outsourcing of specified directories into memory on bootup and
# takes care of synchronization/backup on system shutdown.
#
# Version 1.4, 2010-04-26, by Alexander Koch
#
 
# includes
 
. /etc/rc.conf
. /etc/rc.d/functions
 
 
# configuration (syntax is: [persist. storage]:[mountpoint]:[mount options])
 
DISKS=('/home/alex/.ramdisks/_mozilla:/home/alex/.mozilla:size=100M,uid=1000,gid=100' \
	   'empty:/home/alex/.adobe:size=10M,uid=1000,gid=100' \
	   'empty:/home/alex/.macromedia:size=10M,uid=1000,gid=100')
 
 
# helper functions
 
function activate_rd() {
	[ -d "$1" ] || [ "$1" = "empty" ] || return 1
	[ -d "$2" ] || return 1
	mount | grep "$2" &>/dev/null && return 1
	MNT="mount -t tmpfs"
	[ -z "$3" ] || MNT="$MNT -o $3"
	$MNT none "$2"
	[ $? -gt 0 ] && return 1
	if [ "$1" != "empty" ]; then
		for D in $1/.* $1/*; do
			[ "$(basename "$D")" == "." ] && continue
			[ "$(basename "$D")" == ".." ] && continue
			rsync -axq "$D" "$2" &>/dev/null
			if [ $? -gt 0 ]; then
				umount "$2"
				return 1
			fi
		done
	fi
	return 0
}
 
function backup_rd() {
	mount | grep "$1" &>/dev/null || return 0
	if [ "$2" != "empty" ]; then
		for D in $1/.* $1/*; do
			[ "$(basename "$D")" == "." ] && continue
			[ "$(basename "$D")" == ".." ] && continue
			rsync -axq --delete "$D" "$2" &>/dev/null
			if [ $? -gt 0 ]; then
				tar -cf "/root/$(basename "$2")-failed.tar" "$1"
				return 1
			fi
		done
	fi
	umount "$1" || return 1
	return 0
}
 
 
# main logic
 
case $1 in
	start)
		stat_busy "Mounting ramdisks"
		error=0
		for M in ${DISKS[@]}; do
			FROM="$(echo "$M" | cut -d ':' -f 1)"
			TO="$(echo "$M" | cut -d ':' -f 2)"
			OPTS="$(echo "$M" | cut -d ':' -f 3)"
			activate_rd "$FROM" "$TO" "$OPTS" || error=1
		done
		if [ $error -eq 0 ]; then
			add_daemon ramdisks
			stat_done
		else
			stat_fail
			exit 1
		fi
		;;
	stop)
		stat_busy "Saving ramdisks"
		error=0
		for M in ${DISKS[@]}; do
			FROM="$(echo "$M" | cut -d ':' -f 2)"
			TO="$(echo "$M" | cut -d ':' -f 1)"
			backup_rd "$FROM" "$TO" || error=1
		done
		if [ $error -eq 0 ]; then
			rm_daemon ramdisks
			stat_done
		else
			stat_fail
			echo -n "WARNING: failed to save ramdisk(s), tried to make "
			echo "backup(s) under /root."
			echo "Hit enter to proceed shutdown."
			read DUMMY
			exit 1
		fi
		;;
	restart)
		if ! ck_daemon ramdisks; then
			"$0" stop && sleep 3
		fi
		"$0" start
		;;
	*)
		echo "usage: $0 {start|stop|restart}"
		;;
esac
 
exit 0

Arch ramdisk-script 1.3

Mein Arch ramdisk-script hat ein weiteres Update erfahren, die Konfiguration ist nun mehr nach KISS und dot-Ordner werden korrekt behandelt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/bin/sh
 
#
# Manages outsourcing of specified directories into memory on bootup and
# takes care of synchronization/backup on system shutdown.
#
# Version 1.3, 2010-03-15, by Alexander Koch
#
 
# includes
 
. /etc/rc.conf
. /etc/rc.d/functions
 
 
# configuration (syntax is: [persist. storage]:[mountpoint]:[mount options])
 
DISKS=('/home/alex/.ramdisks/_mozilla:/home/alex/.mozilla:size=100M,uid=1000,gid=100' \
	   'empty:/home/alex/.adobe:size=10M,uid=1000,gid=100' \
	   'empty:/home/alex/.macromedia:size=10M,uid=1000,gid=100')
 
 
# helper functions
 
function activate_rd() {
	[ -d "$1" ] || [ "$1" = "empty" ] || return 1
	[ -d "$2" ] || return 1
	mount | grep "$2" &>/dev/null && return 1
	MNT="mount -t tmpfs"
	[ -z "$3" ] || MNT="$MNT -o $3"
	$MNT none "$2"
	[ $? -gt 0 ] && return 1
	if [ "$1" != "empty" ]; then
		for D in $1/.* $1/*; do
			[ "$(basename "$D")" == "." ] && continue
			[ "$(basename "$D")" == ".." ] && continue
			rsync -axq "$D" "$2" &>/dev/null
			if [ $? -gt 0 ]; then
				umount "$2"
				return 1
			fi
		done
	fi
	return 0
}
 
function backup_rd() {
	mount | grep "$1" &>/dev/null || return 0
	if [ "$2" != "empty" ]; then
		for D in $1/.* $1/*; do
			[ "$(basename "$D")" == "." ] && continue
			[ "$(basename "$D")" == ".." ] && continue
			rsync -axq "$D" "$2" &>/dev/null
			if [ $? -gt 0 ]; then
				tar -cf "/root/$(basename "$2")-failed.tar" "$1"
				return 1
			fi
		done
	fi
	umount "$1" || return 1
	return 0
}
 
 
# main logic
 
case $1 in
	start)
		stat_busy "Mounting ramdisks"
		error=0
		for M in ${DISKS[@]}; do
			FROM="$(echo "$M" | cut -d ':' -f 1)"
			TO="$(echo "$M" | cut -d ':' -f 2)"
			OPTS="$(echo "$M" | cut -d ':' -f 3)"
			activate_rd "$FROM" "$TO" "$OPTS" || error=1
		done
		if [ $error -eq 0 ]; then
			add_daemon ramdisks
			stat_done
		else
			stat_fail
			exit 1
		fi
		;;
	stop)
		stat_busy "Saving ramdisks"
		error=0
		for M in ${DISKS[@]}; do
			FROM="$(echo "$M" | cut -d ':' -f 2)"
			TO="$(echo "$M" | cut -d ':' -f 1)"
			backup_rd "$FROM" "$TO" || error=1
		done
		if [ $error -eq 0 ]; then
			rm_daemon ramdisks
			stat_done
		else
			stat_fail
			echo -n "WARNING: failed to save ramdisk(s), tried to make "
			echo "backup(s) under /root."
			echo "Hit enter to proceed shutdown."
			read DUMMY
			exit 1
		fi
		;;
	restart)
		if ! ck_daemon ramdisks; then
			"$0" stop && sleep 3
		fi
		"$0" start
		;;
	*)
		echo "usage: $0 {start|stop|restart}"
		;;
esac
 
exit 0

Automatische Vhosts mit Lighttpd

Mein bereits erwähntes lighttpd-vhost-script hat ein Update erfahren und unterstützt jetzt Subdomains und Vhost- sowie Subdomain-spezifische configs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash
 
VHOST_ROOT="/var/www"
VHOST_DEF="default"
VHOST_CONF="vhost.conf"
SBD_ROOT="subdomains"
DOC_ROOT="htdocs"
 
for VHOST in $(find $VHOST_ROOT -mindepth 1 -maxdepth 1 -type d -exec basename {} \;); do
 
	# skip default vhost
	if [ "$VHOST_DEF" == "$VHOST" ]; then
        continue
    fi
 
	echo "\$HTTP[\"host\"] =~ \"^(www\.|)$VHOST\" {"
	echo "  server.document-root = \"$VHOST_ROOT/$VHOST/$DOC_ROOT\"" 
	echo "  accesslog.filename = \"/var/log/lighttpd/$VHOST.access.log\""
	if [ -e "$VHOST_ROOT/$VHOST/$VHOST_CONF" ]; then
		# include vhost config
		cat "$VHOST_ROOT/$VHOST/$VHOST_CONF"
	fi
	echo "}"
	echo ""
 
	# subdomains
	if [ -d "$VHOST_ROOT/$VHOST/$SBD_ROOT" ]; then
		for SBD in $(find $VHOST_ROOT/$VHOST/$SBD_ROOT -mindepth 1 -maxdepth 1 -type d -exec basename {} \;); do
			echo "\$HTTP[\"host\"] =~ \"^$SBD.$VHOST\" {"
			echo "  server.document-root = \"$VHOST_ROOT/$VHOST/$SBD_ROOT/$SBD/$DOC_ROOT\""
			echo "  accesslog.filename = \"/var/log/lighttpd/$VHOST.access.log\""
			if [ -e "$VHOST_ROOT/$VHOST/$SBD_ROOT/$SBD/$VHOST_CONF" ]; then
				# include subdomain's custom config
				cat "$VHOST_ROOT/$VHOST/$SBD_ROOT/$SBD/$VHOST_CONF"
			fi
			echo "}"
		done
		echo ""
	fi
done

etc-update

Aus meiner Gentoo-Zeit habe ich oft etc-update vermisst, was sich um das Aktualisieren von Configs kümmert. Als Arch-Pendant hier mal mein Ansatz in Form eines Bash-Scripts. Es findet aktualisierende und verwaiste .pacnew, sowie überholte .pacsave und arbeitet sie interaktiv sequentiell ab.

#!/bin/sh

DIR="/etc"

if [ $(id -u) -gt 0 ]; then
	sudo $0
	exit $?
fi

function work()
{
	ANS="z"
	while echo "$ANS" | egrep -v '^[0-3]$' &>/dev/null; do
		echo "$1:"
		echo "  [0] colordiff (old->new)"
		echo "  [1] upgrade (overwrite)"
		echo "  [2] keep (delete .pacnew)"
		echo "  [3] skip"
		echo -n "choice: "
		read ANS
	done
	case $ANS in
		0)
			colordiff "$1" "$2"
			work "$1" "$2"
			;;
		1)
			mv "$2" "$1" || exit 1
			;;
		2)
			rm "$2" || exit 1
			;;
		3)
			true
			;;
		*)
			work "$1" "$2"
			;;
	esac
}

PACNEW="$(find $DIR -iname '*.pacnew' 2>/dev/null)"
PACSAV="$(find $DIR -iname '*.pacsave' 2>/dev/null)"

for FILE in $PACNEW; do
	CONF="${FILE%.pacnew}"
	if [ -e "$CONF" ]; then
		work "$CONF" "$FILE"
	else
		echo -n "$FILE orphaned, delete? [Y/n] "
		read ANS
		if [ "$ANS" == "Y" -o "$ANS" == "y" -o "$ANS" == "" ]; then
			rm "$FILE" || exit 1
		fi
	fi
done

for FILE in $PACSAV; do
	CONF="${FILE%.pacsave}"
	if [ -e "$CONF" ]; then
		echo -n "$CONF obsolete ($(basename $CONF) present), delete? [Y/n] "
	else
		echo -n "$FILE remaining, delete? [Y/n] "
	fi
	read ANS
	if [ "$ANS" == "Y" -o "$ANS" == "y" -o "$ANS" == "" ]; then
			rm "$FILE" || exit 1
	fi
done

exit 0

Wie immer der Hinweis: Benutztung auf eigene Gefahr!

Update: Ja, ich kenne yaourt und weiß um yaourt -C Bescheid *grml*, aber warum yaourt benutzen, wenn man auch ein Bashscript schreiben kann? ;)

vcp – Verbose cp

Eine Sache, die mich seit einigen Monaten immer wieder ganze Abende gekostet hat und über die ich schon lange bloggen wollte, aber nie Zeit fand: Verbose cp, aka vcp.

vcp soll das Gleiche tun wie cp, allerdings mit Fortschrittsanzeige und ETA. Geboren wurde die Idee dafür, als ich einen Aufhänger gesucht habe, endlich mal richtig C zu lernen, und mich daran erinnerte, wie sehr ich die gepatchten coreutils aus Gentoo-Zeiten vermisse, wenn ich in einer ssh-Session mal wieder am Verschieben einer größeren Datei bin und mich frage, wann das dämliche Ding endlich fertig ist.

Ich habe versucht, den Code so simpel wie möglich zu halten, um KISS treu zu bleiben. Gelungen ist mir das sicher nicht überall, aber da es ja ein Lernprojekt ist und ich noch keinen umfassenden Überblick über die Standardbibliotheken habe, sehe ich das nicht als tragisch an.
Im Moment befindet sich das Tool in einer schon recht brauchbaren Phase: reguläre Dateien und Ordner (yey, Rekursion! :) )  können bereits kopiert werden, die Fortschrittsanzeige ist ebenfalls implementiert und liefert Datei- und Jobstatus, sowie ETA und gemittelte Geschwindigkeit. Ebenfalls praktisch: fehlgeschlagene Dateien werden übergangen und erst am Ende bemängelt, d.h. man muss nicht bei jedem Fehler immer von vorne beginnen, sondern kann sich beim zweiten Versuch auf die Problemfälle konzentrieren und bereits vorhandene Dateien automatisch überspringen lassen.

Um nicht in detaillierte Beschreibungen der Funktionalität abzudriften sei an dieser Stelle genug der Vorstellung, wer bereits einen Blich auf meine Arbeit werfen möchte, kann den Code (steht unter GPLv3) über http://github.com/lynix/vcp beziehen und ausprobieren. Es sei noch darauf hingewiesen, dass sich das Tool in der Entwicklung befindet, Benutzung auf eigene Gefahr!

Sobald ich mehr Zeit habe, bekommt das Ding dann auch noch eine rudimentäre Homepage mit besserer Dokumentation.

Link-Grabbing per Fake-Downloader

Wer über Nacht große Downloads auf der Xorg-losen Box laufen lassen will, braucht einen wget-tauglichen Link. Oft wird gerade dieser jedoch von der anbietenden Seite auf Biegen und Brechen zu verschleiern versucht. Es gibt zwar für jede Taktik auch eine geeignete Gegenmaßnahme (sonst würde der Download per Browser ja auch nicht funktionieren), wer sich aber das Suchen und Basteln sparen möchte und auch gern mal viele Links ohne großen Aufwand zusammenklicken will, kann folgende Methode nutzen:

Über das Firefox-Addon FlashGot lässt sich ein benutzerdefinierter Downloadmanager einrichten, an den FlashGot dann die URL und wahlweise diverse andere Informationen wie Header, etc. weiter gibt.
Als so ein Downloadmanager dient beispielsweise folgendes kleines Bash-script, welches alle ihm übergebenen Links eines bekannten 1-Click-Hosters ( ;) ) unter ~/links.txt ablegt:

#!/bin/sh
 
echo "$1" | sed -e 's/\/.*\.rapid/\/\/rapid/' >> ~/links.txt
exit 0

xfce4-notifyd: bold summary

Wieder ein ziemlicher dirty-hack, der mir einen Dorn aus dem Auge zieht – diesmal an xfce4-notifyd, dem lightweight-Ersatz für notification-daemon.

Gestört hatte mich die Formatierung der Popup-Überschriften (summaries), die sich nicht von der des Textes unterscheidet, weshalb man Text und Überschrift auf den ersten Blick kaum trennen konnte. Ein Eingriff in die Sourcen macht die Überschriften bei mir jetzt fett, hier der Patch (für die xfce-notify-window.c aus xfce4-notifyd-0.1.0).

Wenn jemand eine Lösung über die gtkrc der Themes findet, möge er mich doch bitte erleuchten ;)

based on theme by WordPress Themes