Munin Plugin für postfix-policyd-spf-python

Nachdem ich nach DKIM auch SPF auf meinem Mailserver aufgesetzt hatte (Paket postfix-policyd-spf-python) wollte ich natürlich auch sehen, welchen Effekt dieser zusätzliche Filter auf den Mailverkehr hat.

Wieder ein Grund zur Bash-Scripterei! :)  Folgendes kleine Plugin habe ich heute Morgen runtergehackt:

#!/bin/bash
#
#   Munin plugin to count postfix-policyd-spf-python results
#           2012 Alexander Koch <lynix47@gmail.com> 
# 
# Parameters understood:
#	config		(required)
#	autoconf 	(optional - used by munin-config)
# 
# Config variables:
#       logfile      - Where to find the postfix log (mail.log)
#
# Add the following line to a file in /etc/munin/plugin-conf.d:
# 	env.logfile /var/log/your/mail.log
#
# Magic markers (optional - used by munin-config and installation scripts):
#
#%# family=auto
#%# capabilities=autoconf
 
 
#
# Configuration
#
 
STAT_FILE=${STAT_FILE:-/var/lib/munin/plugin-state/plugin-plcyd-spf-python.state}
LOGFILE=${logfile:-/var/log/mail.log}
 
if [ "$1" = "autoconf" ]; then
	echo yes
	exit 0
fi
 
if [ "$1" = "config" ]; then
	echo 'graph_title SPF Check Results'
	echo 'graph_category postfix'
	echo 'graph_args --base 1000 -l 0'
	echo 'graph_vlabel Count/s'
 
	echo 'count_pass.label Pass'
	echo 'count_pass.type DERIVE'
	echo 'count_pass.min 0'
	echo 'count_pass.colour 00cc00'
	echo 'count_fail.label Fail'
	echo 'count_fail.type DERIVE'
	echo 'count_fail.min 0'
	echo 'count_fail.colour cc0000'
	echo 'count_none.label None'
	echo 'count_none.type DERIVE'
	echo 'count_none.min 0'
	echo 'count_none.colour 0066b3'
	echo 'count_temperror.label Temperror'
	echo 'count_temperror.type DERIVE'
	echo 'count_temperror.min 0'
	echo 'count_temperror.colour ff8000'
	echo 'count_neutral.label Neutral'
	echo 'count_neutral.type DERIVE'
	echo 'count_neutral.min 0'
	echo 'count_neutral.colour ffcc00'
 
	exit 0
fi
 
 
#
# Log parsing
#
 
function get_log_count() {
	egrep "policyd-spf\[[0-9]+\]: $1;" "$LOGFILE" | grep "$(date '+%b %e')" | wc -l
}
 
PASS=$(get_log_count "Pass")
FAIL=$(get_log_count "Fail")
NONE=$(get_log_count "None")
TEMPERR=$(get_log_count "Temperror")
NEUTRAL=$(get_log_count "Neutral")
 
echo "count_pass.value $PASS"
echo "count_fail.value $FAIL"
echo "count_none.value $NONE"
echo "count_temperror.value $TEMPERR"
echo "count_neutral.value $NEUTRAL"
 
 
exit 0

Wie immer gibts den Code auch in meinem GitHub-Repo.

Ein Screenshot des produzierten Graphen folgt, sobald ich genug Daten für eine vollständige Periode (24h) gesammelt habe. Edit: hier der Screeny, anscheinend habe ich zu wenig Traffic auf dem Mailserver ;)

hdd-spindown.sh

Mal wieder Zeit gefunden, einen schon leicht angestaubten Punkt auf meiner 2code-Liste abzuhaken:

Ein Bash-Script, das Platten bei Inaktivität nach definierbarem Timeout per hdparm -y in Standby schickt. Für mich sehr nützlich bei SATA-Platten, die sich nicht per hdparm -S konfigurieren lassen.

Gehostet wie immer auf github, oder direkt hier:

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
#!/bin/bash
 
#
# Automatic disk standby using kernel diskstats and hdparm
#
# Version 1.1, 2011 by Alexander Koch <lynix47@gmail.com>
#
 
 
# DEVICES syntax: DEVICE:TIMEOUT_SEC
DEVICES=( "sda:120" "sdb:120" )
 
function device_worker() {
	test -e "/dev/$1" || return 1
	logger -t hdd-spindown.sh "spawned monitor thread for $1"
	COUNT_R=0
	COUNT_W=0
	while true; do
		NEW_R=$(awk '{print $1}' /sys/block/$1/stat)
		NEW_W=$(awk '{print $5}' /sys/block/$1/stat)
		if [ $COUNT_R -eq $NEW_R ] && [ $COUNT_W -eq $NEW_W ]; then
			if hdparm -C /dev/$1 | grep active &>/dev/null; then
				logger -t hdd-spindown.sh "suspending $1"
				hdparm -qy /dev/$1
				if [ $? -gt 0 ]; then
					logger "failed to suspend $1"
					return 1
				fi
			fi
		else
			COUNT_R=$NEW_R
			COUNT_W=$NEW_W
		fi
		sleep $2
	done
}
 
for D in ${DEVICES[@]}; do
	device_worker $(echo "$D" | cut -d ':' -f 1) $(echo "$D" | cut -d ':' -f 2) &
done
 
exit 0

Auf Performance-Optimierungen habe ich bewusst verzichtet und alles möglichst simpel gehalten.

Funktionsbedingt ist der einstellbare Wert für den Timeout (T) übrigens nicht hart; die reale Zeit an Inaktivität ti genügt der Bedingung T ≤ ti < 2T.

Thunderbird 3 unter KDE 4

Déjà-vu: Back to Thunderbird, diesmal unter KDE und von KMail aus ;)

Nach immer mehr Frust über die IMHO lausige IMAP-Anbindung in KMail (aus KDE-SC 4.4.6) und dem immer noch nicht erschienenen PIM-Teil von KDE SC 4.5 bin ich wieder zu Thunderbird gewechselt. Hier mein Setup, inkl. etwas Handarbeit bei der KDE-Integration.

Theme

OxyBird 2, verwendet Oxygen-Icons

Mail-Notifications

Der etwas haarigere Teil. Nach diversen getesteten Plugins bin ich bei folgender Kombination gelandet: Mailbox Alert, eingestellt einen eigenen Wrapper aufzurufen (tb-notify.sh %sender %subject). Selbiger sieht dann so aus:

#!/bin/bash
 
# notification-wrapper for Thunderbird under KDE
 
SOUND="/usr/share/sounds/KDE-Im-New-Mail.ogg"
PLAYER="/usr/bin/ogg123"
ICON="/usr/share/icons/oxygen/48x48/status/mail-unread-new.png"
 
$PLAYER "$SOUND" &>/dev/null &
notify-send -u normal -i "$ICON" "$1" "$2"
 
exit 0

Sonstige Plugins

Config-Tweaks (about:config)

  • mail.server.default.archive_granularity = 0
    Unterbindet das Erstellen von Unterordnern im Archiv.
  • mail.tabs.autohide = 1
    Tabs nur anzeigen wenn mehr als eins vorhanden.

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 :)

iptables init-script für Arch

Ja, das vom Paket iptables mitgebrachte init-script leistet wunderbare Dienste. Nein, es besteht kein akuter Grund, eine Alternative zu schreiben…
Einen Nachteil hat es schon: die Konfiguration wird in einem nicht kommentierbaren Format hinterlegt, was bei mir in letzter Zeit ständig zur Frage “WTF hat doch gleich dieser Port da verloren? Was lässt die rule da nochmal durch?” geführt hat.

<bash-addicted>Yep, eindeutige Notwenigkeit für ein selbst gehämmertes, kommentierbares  Script!</bash-addicted> Wie in guten alten Debian-Zeiten übernimmt jetzt also bei mir ein einfaches, aber für den Job völlig ausreichendes init-script den Job. Wer es verwenden mag:

#!/bin/bash
 
#
#   easy-to-edit iptables init script for Arch
#           2010 by Alexander Koch
#
 
 
# TCP services: ssh
SERVICES_TCP=( 22 )
# UDP services:
SERVICES_UDP=( )
 
. /etc/rc.conf
. /etc/rc.d/functions
 
if [ -e "/etc/conf.d/iptables" ]; then
    . /etc/conf.d/iptables
fi
if [ -z "$IPTABLES" ]; then
    IPTABLES="/usr/sbin/iptables"
fi
if ! [ -x "$IPTABLES" ]; then
    echo "unable to execute iptables binary: $IPTABLES"
    exit 1
fi
 
function reset_tables() {
    ERR=0
    $IPTABLES -F || ERR=1
    $IPTABLES -X || ERR=1
    $IPTABLES -P INPUT ACCEPT || ERR=1
    $IPTABLES -P OUTPUT ACCEPT || ERR=1
    if [ $IPTABLES_FORWARD -eq 1 ]; then
        $IPTABLES -P FORWARD ACCEPT || ERR=1
        echo 1 >/proc/sys/net/ipv4/ip_forward || ERR=1
    else
        $IPTABLES -P FORWARD DROP || ERR=1
        echo 0 >/proc/sys/net/ipv4/ip_forward || ERR=1
    fi
 
    return $ERR
}
 
function setup_tables() {
    ERR=0
 
    # setup prevention chain against common attacks
    $IPTABLES -N preventions || ERR=1
    $IPTABLES -A preventions -f -j DROP || ERR=1                           # frags
    $IPTABLES -A preventions -p tcp --tcp-flags ALL ALL -j DROP || ERR=1   # XMAS
    $IPTABLES -A preventions -p tcp --tcp-flags ALL NONE -j DROP || ERR=1  # null
 
    # setup services chain
    $IPTABLES -N services || ERR=1
    for PORT in ${SERVICES_TCP[@]}; do
        $IPTABLES -A services -p tcp --dport $PORT -j ACCEPT || ERR=1
    done
    for PORT in ${SERVICES_UDP[@]}; do
        $IPTABLES -A services -p udp --dport $PORT -j ACCEPT || ERR=1
    done
 
    # allow incoming ping requests
    iptables -A services -p icmp --icmp-type echo-request -j ACCEPT || ERR=1
 
    # setup main chains
    $IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT || ERR=1
    $IPTABLES -A INPUT -i lo -j ACCEPT || ERR=1
    $IPTABLES -A INPUT -j preventions || ERR=1
    $IPTABLES -A INPUT -m state --state NEW -j services || ERR=1
    $IPTABLES -A INPUT -p tcp -j REJECT --reject-with tcp-reset || ERR=1
    $IPTABLES -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable || ERR=1
    $IPTABLES -P INPUT DROP || ERR=1
 
    return $ERR
}
 
case "$1" in
    start)
        stat_busy "Loading IP Tables"
        reset_tables
        if ! setup_tables; then
            stat_fail
            exit 1
        else
            add_daemon miptables
            stat_done
        fi
        ;;
    stop)
        stat_busy "Flushing IP Tables"
        if reset_tables; then
            rm_daemon miptables
            stat_done
        else
            stat_fail
            exit 1
        fi
        ;;
    restart)
        if ! ck_daemon miptables; then
            rm_daemon miptables
        fi
        $0 start
        exit $?
        ;;
    *)
        echo "usage: $0 {start|stop|restart}"
        ;;
esac
 
exit 0

Gefiltert werden nur eingehende Pakete; related und established Pakete werden ebenfalls ohne weitere Beachtung durchgelassen, ebenso alles über loopback. Für neue Pakete werden zuerst ein paar Vulnerability-Checks durchgeführt. Nach Außen wird ein Verhalten wie ohne iptables emuliert (z.B. REJECTs mit tcp-reset).

Bugreports wie immer willkommen, und Benutzung auf eigene Gefahr!

Update 31.07.10: Bugfixed :)

Arch rc.sysinit: LUKS parallel

Im Arch Bootscript /etc/rc.sysinit werden u.A. die per /etc/crypttab definierten verschlüsselten Volumes geöffnet und gemountet – sequentiell. Da ein luksOpen-Aufruf generell schon recht lange dauert, kommen bei mehreren solcher Volumes schnell einige Sekunden zusammen.

Auf einer Kiste mit fünf LUKS-Volumes kam mir die Idee, die entsprechende Funktion mal per “&” zu forken und das Ganze so ein wenig zu parallelisieren.

In wie fern das jetzt tatsächlich im messbaren Bereich liegt, sei mal dahingestellt. Ich bilde mir jedenfalls erfolgreich einen Geschwindigkeits-zuwachs ein, und da der Patch meines Erachtens recht unkritisch ist, bleibe ich dabei :)

Wer es ausprobieren mag:

--- /etc/rc.sysinit.backup      2010-01-24 15:35:12.000000000 +0100
+++ /etc/rc.sysinit             2010-05-04 18:57:53.380890577 +0200
@@ -149,7 +149,7 @@
                        cpass="$3"
                        shift 3
                        copts="$*"
-                       stat_append "${cname}.."
+                       #stat_append "${cname}.."
                        # For some fun reason, the parameter ordering varies for
                        # LUKS and non-LUKS devices.  Joy.
                        if [ "${cpass}" = "SWAP" ]; then
@@ -188,15 +188,16 @@
                        fi
                        if [ $? -ne 0 ]; then
                                csfailed=1
-                               stat_append "failed "
+                               stat_append "${cname} failed "
                        else
-                               stat_append "ok "
+                               stat_append "${cname} ok "
                        fi
                fi
        }
        while read line; do
-               eval do_crypt "$line"
+               eval do_crypt "$line" &
        done </etc/crypttab
+       wait
        if [ $csfailed -eq 0 ]; then
                stat_done
        else

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

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? ;)

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