Entries tagged as tipps and tricks
Related tags
Monday, 8. March 2010
sed revisited
Der Eintrag kommt noch, versprochen. Für alle Ungeduldigen gibt es hier bereits eine Vorschau auf den 3. Teil (inklusive Teil 1 und 2).
Tuesday, 12. January 2010
Sicheres Löschen eines Datenträgers
Denn man möchte vermutlich weder, dass irgendwelche geschäftlichen Daten Fremden in die Hände kommen, noch wird man scharf drauf sein, die privaten Bilder von Tante Erna aus ihrem Urlaub in Hinterzupfingen anderen Menschen zu präsentieren.
Dabei geht es nicht um sensible private Daten wie Lebensläufe, Bankdaten, Kontoauszüge oder wichtige geschäftliche Daten, nein vielmehr geht es um alle vorhandenen Daten, bzw. auch vermeintlich schon gelöschte Daten. Gelöscht heißt nämlich, dass das Betriebssystem nur den Verweis auf die Daten löscht bzw. den Bereich intern als leer markiert, so dass dort neue Daten gespeichert werden können.
Diese Daten sind nicht umsonst privater Natur und genau das sollen sie auch bleiben. Das heißt nicht, dass man etwas zu verstecken hat, denn schließlich laufen wir ja auch alle nicht grundlos mit Kleidung rum.
Nach gängiger Meinung genügt zum sicheren Löschen das Überschreiben der kompletten Festplatte mit einem Zufallsmuster. Gerüchte, wonach selbst überschriebene Daten aus "Restmagnetspuren" der Spurränder von Festplatten wiederhergestellt werden konnten, gehören wohl ins Reich der Verschwörungstheorien und scheinen nur Spekulationen zu sein. (Update: Ein entsprechender Artikel von Peter Gutmann, beschreibt daher eine Methodik zum sicheren Löschen von Daten durch mehrmaliges Überschreiben mit unterschiedlichen Bitmustern. Zu beachten ist aber, dass dieser Artikel von 1996 stammt und wohl mittlerweile durch die vergrößerte Speicherdichte heutzutage nicht mehr allgemein gültig ist. Es stellt sich sogar die Frage, ob einfaches Überschreiben durch Nullen nicht sogar eine ausreichende Sicherheit beim Überschreiben verspricht.)
Um das zu erreichen, genügt bei einer gängigen Linuxdistribution der dd Befehl. Damit kann man sehr einfach Daten auf die Festplatte schreiben. Die gängige Empfehlung ist dabei, dd if=/dev/urandom of=/dev/sda bs=1M auszuführen. Damit liest man aus dem Pseudo-Zufallspool des Systems und schreibt die Daten als 1 MB große Blöche auf das Gerät /dev/sda. Das ist grundsätzlich auch ok, das einzige Problem, was man dabei hat ist, dass der Zufallspool normalerweise nicht sehr gut gefüllt ist und nur relativ langsam gelesen werden kann.
Bei heutigen Festplattengenerationen mit mehreren hundert Gigabyte Speicher, kann da schon einmal ein Nacht für das Überschreiben drauf gehen (oder vielleicht sogar mehr, ich habe das noch nicht so genau getestet).
Schneller und äquivalent sicher ist es dagegen, die Festplatte mit Nullen zu beschreiben, die danach verschlüsselt werden. Dazu kann man cryptsetup verwenden, was mittlerweile wohl bei allen modernen Linux Distributionen dabei sein sollte:
# dd if=/dev/zero of=/dev/mapper/sda bs=1M
# cryptsetup remove sda
Hier legt man eine logische Blockschicht über dem Gerät /dev/sda an, dass mit einem Zufallsschlüssel, der aus dem Zufallspool /dev/random kommt, verschlüsselt wird. Alles was auf dem neuen Blockschicht /dev/mapper/sda geschrieben wird, wird intern verschlüsselt auf das eigentliche Gerät /dev/sda geschrieben. Der Schlüssel ist eigentlich egal, er wird im Prinzip nur genutzt, um ein zufälliges Bitmuster aus den Nullen zu generieren und zu schreiben.
Damit braucht das System nicht auf den langsamen Zufalls-Entropiepool zu warten (es muß nämlich von dort nur zur Erstellung des Schlüssels einmalig 256bit lesen), sondern kann sehr schnell lesen die Nullen lesen. Durch die Verschlüsselung verlangsamt sich die Schreibgeschwindigkeit zwar, ist aber dennoch größer als bei der vorherigen Methode. In Zeiten immer schnellerer CPUs (zumindest in Desktop System) fällt der Geschwindigkeitsverlust wahrscheinlich immer geringer aus und wer von Anfang an ein verschlüsseltes Gesamtsystem verwendet, der wird gar keine Geschwindigkeitseinbußen bemerken.
Getestet habe ich das Ganze auch mal mit einer leeren 10GB Partition:
1000+0 Datensätze ein
1000+0 Datensätze aus
10485760000 Bytes (10 GB) kopiert, 228,142 s, 46,0 MB/s
root@ubuntu:/temp# losetup /dev/loop2 big_file
root@ubuntu:/temp# time dd if=/dev/urandom of=/dev/loop2 bs=1M
dd: Schreiben von „/dev/loop2“: No space left on device
10000+1 Datensätze ein
9999+1 Datensätze aus
10485760000 Bytes (10 GB) kopiert, 1786,48 s, 5,9 MB/s
real 29m46.537s
user 0m0.050s
sys 25m36.450s
root@ubuntu:/temp#
root@ubuntu:/temp# cryptsetup -d /dev/random -c aes-xts-plain create loop /dev/loop2
root@ubuntu:/temp# time dd if=/dev/zero of=/dev/mapper/loop bs=1M
dd: Schreiben von „/dev/mapper/loop“: No space left on device
10001+0 Datensätze ein
10000+0 Datensätze aus
10485760000 Bytes (10 GB) kopiert, 205,879 s, 50,9 MB/s
real 3m25.885s
user 0m0.000s
sys 0m12.290s
Wie man sieht, habe ich hier eine durchschnittliche Schreibgeschwindigkeit von 5,9MB/s mittels der traditionellen Methode erhalten. Durch das Verschlüsseln, konnte die Schreibgeschwindigkeit fast verneunfacht werden. Noch drastischer sind die absoluten Zeiten: fast 30 Minuten anstelle von 3,5 Minuten.
Das ist natürlich kein Benchmark, sondern soll nur zeigen, welch drastischen Unterschiede zwischen den Methoden existieren. Spielen kann man eventuell noch mit dem Blocksize Parameter, der in diesem Beispiel auf 1 Megabyte gesetzt war. Es ist nicht auszuschließen, dass es mit einem anderen Verschlüsselungsalgorithmus (hier aes-xts-plain) sogar noch schneller geht. (einfahcer Benchmark verschiedener Verschlüsselungsalgorithmen und noch ein Benchmark, ausführlicher)
Disclaimer: Unbedingt zweimal prüfen, auf welches Gerät man schreibt, bevor man sich sein System zerschießt. Dieses Gerät sollte auch nicht anderweitig parallel verwendet werden, sonst besteht die Gefahr, dass noch etwaige Daten nicht überschrieben werden konnten, weil sie noch geöffnet waren.
Wednesday, 11. November 2009
bash: eternal history
Das ist verwirrend und wenn man Pech hat, werden genau die Befehle überschrieben, die man unbedingt wieder benötigt hätte. Folgendermaßen bekommt man ein ewiges Logfile für die Bash:
HISTTIMEFORMAT='%F %T '
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND ; }" 'echo $USER $(history 1) >> ~/.history'
Mit HISTTIMEFORMAT wird angegeben, wie das Datum für jeden Eintrag gespeichert werden soll. Danach gibt man an, dass jedesmal wenn der Prompt angezeigt wird, der vorige Befehl gespeichert werden soll (in diesem Fall: "Hänge den vorherigen Befehl an ~/.history an": echo $(history 1) >> ~/.history). $PROMPT_COMMAND gibt an, was ausgeführt werden soll, bevor der PROMPT angezeigt wird. Und ${PROMPT_COMMAND:+$PROMT_COMMAND} definiert, dass der nachfolgende Befehl an die eventuell bereits definierte Variable PROMPT_COMMAND angehängt werden soll.
Die History wird dann im Format
USER INDEX TIMESTAMP COMMMAND
gespeichert. Man kann natürlich noch zusätzliche Infos hinzufügen.
[UPDATE]
Der Vollständigkeit halber möchte ich noch ergänzen, wie man das auch lösen könnte:
~$ unset $HISTFILESIZE
~$ shopt -s histappend
~$ PROMPT_COMMAND='history -a'
Damit sollte auch ein ewiges Logfile geschrieben werden. HISTSIZE gibt die Anzahl der Einträge an, die die aktuelle bash-Session speichert, HISTFILESIZE die Anzahl der Einträge in der .bash_history. Mittels shopt -s histappend wird der bash mitgeteilt, dass die .bash_history nicht jedesmal überschrieben werden soll, sondern neue Einträge immer angehängt werden soll. Und mit PROMPT_COMMAND='history -a' wird eingestellt, dass jedesmal wenn ein Prompt angezeigt wird, der letzte Befehl in die Logdatei angehängt wird.
Das einzige Problem hierbei könnte sein, dass nach einer Zeit die history zu groß wird und damit die bash zuviel Speicher benötigt und unnötig lahm wird.
Wednesday, 29. July 2009
Vergessenes Passwort
Nun ja, also habe ich mir natürlich ein komplexes und sehr langes Passwort ausgedacht. Richtig lang und schwierig zu merken. Dummerweise hatte ich es 10 Minuten später doch wieder vergessen.
Egal was ich tat, Windows ließ mich nicht mehr rein. Normalerweise hilft eine kurze Gedenkminute, aber das brachte diesmal nichts. Ganz kurz fing ich an zu schwitzen, ich sah mich schon zum Support rennen, meinen Rechner geplättet und ein neues Image draufgezogen und damit alle meine Daten weg.
Doch dann fiel mir ein, dass ich ja noch ein zweites Betriebssystem auf dem Laptop habe, in diesem Fall Ubuntu 9.04 installiert durch den Wubi-Installer. Somit hatte ich von da aus zumindest Zugriff auf meine Daten und hätte sie wenigstens noch retten können, bevor ich zum Support laufe und nen halben Tag abschreiben kann. Irgendwann fiel mir zum Glück noch ein, kurz mal zu googeln, ob es nicht von Linux aus eine Möglichkeit gäbe, das Passwort zurückzusetzen. Und tatsächlich, es gibt sie. Und zwar in Form von chntpw.
Also schnell per apt-get installiert, kurz die Doku gelesen und losgelegt (gute Anleitung übrigens):
chntpw version 0.99..., (c) Petter N Hagen
openHive(software): File does not seem to be a registry hive!
Simple registry editor. ? for help.
Funktioniert natürlich nicht, wie es im Netz steht. Super. Immer dann, wenn man sowas ganz dringend braucht, ist die Software borken. Ich fing wieder an zu schwitzen... Nochmal nach der Fehlermeldung gegoogelt und ich fand den folgenden Bug: Launchpad: 293809. Scheint, als wäre chntpw auf x86_64 kaputt. Dabei habe ich nichtmal absichtlich die 64bit Version von Ubuntu installiert. Das hat der Installer von alleine gemacht, ohne mich zu fragen!!!1ELF
Als nächstes versuchte ich dann mit den verschiedenen Images, die auf der Upstream Homepage bereitgestellt werden, einen USB-Stick bootfähig zu machen. Einen Rohling hatte ich nämlich nicht und ein Floppy Drive gibt es nicht mehr am Laptop (Überraschung!). Ging aber nicht, warum auch immer. Also doch zum Support rennen.
Aber halt, im Source, gibt es eine statisch kompilierte Version. Und das war die große Überraschung. Einfach das Source Paket von Upstream runterladen und mit chntpw.static arbeiten. Das funktioniert!
5 Minuten später hatte ich wieder einen funktionierenden Login bei Windows. Und das neue Passwort ist zwar auch wieder kompliziert, aber das kann ich mir merken.
Tuesday, 28. July 2009
Mit mencoder für die PlayStation Portable kodieren
-oac lavc -lavcopts aglobal=1:vglobal=1:vcodec=libx264:acodec=libfaac:vbitrate=640:abitrate=128:\
coder=1:level=21 -lavfopts format=psp Input -o Output
Man kann das ganze auch als Profil unter ~/.mplayer/mencoder.conf speichern:
profile-desc="PSP H.264 encoding profile."
vf=hqdn3d,scale=480:272
af=lavcresample=48000
ofps=30000/1001
ovc=lavc=1
oac=lavc=1
lavcopts=aglobal=1:vglobal=1:vcodec=libx264:acodec=libfaac:vbitrate=640:abitrate=128:coder=1:level=21
of=lavf=1
lavfopts=format=psp
und dann mit mencoder -profile psp Input -o Output passend kodieren
Wednesday, 8. July 2009
Vim Plugin sudoedit.vim
Daher hab ich das Plugin sudoedit.vim geschrieben. Wenn mir sowas wieder passiert, einfach Datei bearbeiten und zum Schluß :SudoWrite eingeben und die Datei wird mittels sudo/su oder mithilfe eines anderen konfigurierbaren Tools geschrieben.
Monday, 6. July 2009
Vim Highlightmark.vim Plugin
Dabei gibt es mindestens noch 2 andere Implementierungen: showmarks.vim und showmarks.vim Ich hab das erst hinterher erfahren, nachdem ich mein eigenes Script geschrieben habe. Ich kenne nämlich keines davon, mein Script funktioniert für mich zufriedenstellend.
Fehler und Anmerkungen nehme ich natürlich gerne entgegen. Dabei fällt mir ein, ich könnte mal wieder häufiger über diesen Editor bloggen. Mal sehen...
Wednesday, 27. May 2009
SSHFS und globaler Namespace
Ich springe bei der Arbeit auf einer Menge von Kisten rum und bearbeite dabei eine Menge Files - nichts besonderes wenn man Systeme administriert bzw. Software entwickelt. In letzter Zeit nutze ich vermehrt SSHFS. Das ist sehr praktisch, da man so die Tools (z.B. svn, vim, ctags, ...) die man auf seiner Workstation konfiguriert und installiert hat nutzen kann sofern man netzwerktechnisch in der Lage ist, eine SSH-Verbindung aufzubauen.
Prinzipiell geht das so:
aptitude install sshfs mkdir /home/mschoechlin/mnt/256bit.org/ sshfs -o idmap=user mschoechlin@256bit.org:/ /home/mschoechlin/mnt/256bit.org/ cat /home/mschoechlin/mnt/256bit.org/etc/fstab
Mit dem Tool "afuse" geht das noch bequemer - nebenbei bekommt man einen globalen Filesystemnamespace:
aptitude install afuse sshfs mkdir ~/sshfs afuse -o mount_template="sshfs -o idmap=user %r:/ %m" -o unmount_template="fusermount -u -z %m" ~/sshfs/ cd ~/sshfs cat user@host/etc/fstab cat host/etc/fstab killall afuse
Sobald man also mit "cd" in das Verzeichnis "~/sshfs/<user>@<hostname>" wechselt springt der "afuse" Automounter an und mountet das System via "sshfs". Dabei wird die UserId, über welche man sich angemeldet hat, immer auf die lokale gemapped. Die Verwendung des SSH-Agent/SSH-Keys ist hier ganz nützlich - andernfalls poppt ein Passwortdialog auf.
Friday, 8. May 2009
Eine kleine Einführung in sed, Teil 2
Wie ich im ersten Teil bereits beschrieben habe, arbeitet man bei sed meist mit Mustern, die bestimmte Teile definieren, an denen Änderungen vorgenommen werden sollen. Diese Muster werden typischerweise durch reguläre Ausdrücke definiert. GNU Sed unterstützt dabei einfache reguläre Ausdrücke (basic regular expressions) bzw. mit dem Schalter -r erweiterte reguläre Ausdrücke (extended regular expressions, z.B. was egrep benutzt). Die wichtigsten Regeln mal kurz erklärt:
^ Anfang der Zeile
$ Ende der Zeile
. irgendein Zeichen
[...] irgendein Zeichen welches innerhalb der eckigen Klammer angegeben ist.
[a-z] passt auf alle Kleinbuchstaben des Alphabets, [abc] entweder auf
a oder auf b oder auf c
[^...] irgendein Zeichen welches nicht innerhalb der eckigen Klammer angegeben
ist. [^a-z] passt auf alle Zeichen, die keine Kleinbuchstaben sind.
\(\) Klammerung (bei erweiterten regulären Ausdrücken ohne Backslash, also ().
Damit kann man sich Ausdrücke merken und später auf sie referenzieren
mit den Variablen \1 bis \10 D.h. man kann auf maximal 10 verschiedene
Zeichenketten referenzieren, mehr geht nicht. Dabei zählt immer die
Reihenfolge der öffnenden Klammer.
(\(a\)b\1 passt auf "aba" aber nicht auf "abba")
* Ein sogenannter Quantifier. Der vorherige Ausdruck kann 0 bis beliebig
oft auftreten, dabei wird ein längerer passender Ausdruck bevorzugt
(sogenannte Greediness, "Gier").
a* passt also auf "", a, aa, aaa, und so weiter, bei einer Zeichenkette
von baah, wird es aber immer auf aa passen.
\? Der vorherige Ausdruck passt genau 0 der 1 Mal (erweiterte reguläre
Ausdrücke: ?)
\+ passt auf den vorherigen Ausdruck 1 mal oder mehr. Längere Treffer
werden dabei bevorzugt. (Bei erweiterten regulären Ausdrücken +).
\{n\} passt auf den vorherigen Ausdruck genau n-Mal. (erweiterte reguläre
Ausdrücke: {n})
\{n,\} passt auf den vorherigen Ausdruck n oder mehrmals. (erweiterte reguläre
Ausdrücke: {n,})
\{n,m\} passt auf den vorherigen Ausdruck n oder m Mal (m>n). Längere Treffer
werden bevorzugt. (erweiterte reguläre Ausdrücke: {n,m})
\{,m\} passt auf den vorherigen Ausdruck maximal m Mal. Längere Treffer werden
bevorzugt. (erweiterte reguläre Ausdrücke: {,m}).
\| Entweder der vorherige Ausdruck oder der nachfolgende Ausdruck.
(bei erweiterten regulären Ausdrücken |). a\|b passt auf a oder auf b.
\n passt auf einen Zeilenumbruch¹ (siehe auch Anmerkung).
\$ passt auf ein $-Zeichen (denn $ steht ja für das Ende der Zeile).
So kann man mit dem Backslash nachstehende Zeichen maskieren. \* passt
auf einen *, und so weiter...
Das ist soweit das Wichtigste zu den regulären Ausdrücken, die von Sed unterstüzt werden. Die Syntax ist nicht so schwer, man muß sich nur merken, welche der vielen Dialekte der regulären Ausdrücke sed beherrscht. Des weiteren unterstüzt sed Posix Character Classes, d.h. das Muster [[:lower:]] passt auf alle Kleinbuchstaben und [[:upper:]] auf alle Großbuchstaben. Außerdem beherrscht sed noch Patterns, die mit einem Backslash anfangen. '\w' passt zum Beispiel auf ein "Word"-Character, als Character-Klasse ausgedrückt: [A-Za-z0-9_], '\W' passt auf ein Non-Word-Character und somit der Umdrehung von '\w' (also [^a-zA-Z0-9_].). Weitere \-Muster werden unterstüzt, ich verweise dafür mal auf das Manual bzw. die Info-Seiten.
¹Des weiteren sollte man beachten, dass sed seinen Input zeilenorientiert liest. D.h. normalerweise wird ein Pattern mit einem '\n' für einen Zeilenumbruch nicht passen. Man kann darum arbeiten, aber man sollte das im Hinterkopf behalten, wenn man '\n' benutzt.
So fortgeschrittene Sachen wie "look-ahead", "look-behind", non-greedy Matches oder non-capturing Groups der Perl-kompatiblen regulären Ausdrücke beherrscht sed leider nicht. (Eine gute Übersicht über die vorhandenen Möglichkeiten gibt die Wikipedia.)
Diese Ausdrücke definieren nun, wo etwas gemacht wird. Wenn man die Zeilennummer weiß, kann man aber auch diese benutzen. Zusätzlich erlaubt es GNU Sed noch Schrittfolgen zu definieren. Also zum Beispiel von Zeile 1 ausgehend, jede zweite (also 1,3,5,7...). 1~2 passt genau auf dieses Muster, während 0~2 jede gerade Zeile ausgibt. Verallgemeinert gesagt x~y, wobei x die Startzeile angibt und y die Schrittfolge. $ als Zeilennummer passt dagegen immer auf die letzte Zeile.
Nun haben wir ganz kurz die Adressmöglichkeiten besprochen. Nun möchte man normalerweise auch was machen. Dafür versteht sed sogenannte Kommandos. Diese Kommandos verstehen normalerweise alle 2-Adressen (nämlich eine Start- und eine Ende-Adresse), eine Adresse
Nun haben wir ganz kurz die Adressmöglichkeiten besprochen. Nun möchte man normalerweise auch was machen. Dafür versteht sed sogenannte Kommandos. Diese Kommandos verstehen entweder keine Adressen (z.B. Sprungangaben und Kommentare), Eine oder keine Adressangaben oder 2 Adressen (nämlich Start- und Ende-Adresse).
Die folgenden Kommandos kennt dabei Gnu Sed:
'#' Kennzeichnet einen Kommentar
's/x/y/' ersetze x durch y
':' definiert eine Sprungmarke
'=' Gib die Zeilennummer aus.
'a\
Text' Hängt "Text" als neue Zeile an
'i\
Text' Fügt "Text" in die aktuelle Zeile ein
'c\
Text' Ersetze die aktuelle Zeile durch "Text"
q Beende
r foobar hängt den Inhalt der Datei foobar hinter die aktuelle Zeile ein.
R foobar Fügt eine Zeile der Datei foobar hinter die aktuelle Zeile ein.
b foobar springe zur Sprungmarke foobar
'p' Print (ausgeben des Treffers)
t foobar springe zur Sprungmarke foobar, wenn vorher das letzte s-Kommando
erfolgreich war
t foobar springe zur Sprungmarke foobar, wenn vorher das letzte s-Kommando
nicht erfolgreich war
d lösche aktuell eingelesene Zeile und fang von vorne an
n lese nächste Zeile ein
N lese nächste Zeile ein und hänge an die aktuelle Zeile an.
w foobar Schreibe aktuellen Inhalt in Datei foobar
W foobar Schreibe nur erste Zeile des aktuellen Inputs in Datei (später mehr dazu).
'y/a/b/' Ersetze a durch b (funktioniert so ähnlich wie tr).
Mit y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ werden alle
Kleinbuchstaben durch die Großbuchstaben ersetzt.
! Führe nachfolgendes Kommando für alle Zeilen außer der aktuellen aus.
(Negation)
Normalerweise liest Sed den Input (bis zum Zeilenende \n) in den sogenannten "Pattern Space" und führt die Kommandos im Pattern Space aus und gibt anschließend die Änderungen aus. Daneben gibt es noch einen extra Puffer, den sogenannten Hold Space. In ihm kann man Daten zwischenspeichern und später wieder verwenden. Dafür gibt es die folgenden Kommandos.
D Lösche bis zum ersten Zeilenumbruch im Pattern Space und fang von vorne
an
x Tausche die Inhalte des Pattern Spaces und Hold Spaces aus.
h Kopiere Pattern Space in den Hold Space Puffer
H Hänge Pattern Space an den Hold Space Puffer an
g Kopiere Hold Space Puffer in den Pattern Space
g Hänge Hold Space Puffer an den Pattern Space an
Der Aufbau eines Kommandos ist dabei folgender:
sed -n '3p' gibt Zeile 3 und nur Zeile 3 aus. sed -n '3,5p' gibt alles von Zeile 3 bis 5 aus (inklusive). (Normalerweise wird bei Sed der Input immer auch ausgegeben, mit -n unterdrückt man das und nur wenn man es explizit verlangt (Kommando p) wird etwas ausgegeben).
Das einfachste Kommando ist das '#' Allein für sich macht das gar nichts und gibt einfach alles aus:
sed '#' foobar
Der Fuchs ist rot und rot sind auch Äpfel.
Das gleiche erreicht man auch mit dem "Kommando" ; welches eigentlich verschiedene Kommandos trennt. In diesem Fall führt es ein "Null" Kommando aus und gibt daher alles aus, was es einliest:
sed ';' foobar
Der Fuchs ist rot und rot sind auch Äpfel.
Das verbreiteste Kommando ist sicherlich das s-Kommando. Damit kann man nach einem Muster suchen und dieses durch ein anderes Ersetzen.
Zum Beispiel ersetzt sed 's/rot/grün/' foobar die Zeichenfolge "rot" durch "grün" in der Datei foobar.
sed 's/rot/grün/' foobar
Der Fuchs ist grün und rot sind auch Äpfel.
Naja, aber eigentlich ist der Fuchs ja rot und Äpfel sind grün. Daher kann man dem s-Kommando noch zusätzliche Flags mitgeben. Das bekannteste Flag ist das 'g'. Damit werden alle gefundenen Muster ersetzt:
sed 's/rot/grün/g' foobar
Der Fuchs ist grün und grün sind auch Äpfel.
Man kann aber auch nur bestimmte Muster ersetzen, zum Beispiel nur das 2. Muster:
sed 's/rot/grün/2' foobar
Der Fuchs ist rot und grün sind auch Äpfel.
Wenn kein Flag angegeben wird, wird impliziert die 1 angenommen (also das erste gefundene Muster wird ersetzt).
Ein weiteres Flag ist das i. Hierbei wird das Muster case-insensitiv gesucht, d.h. Klein-/Großbuchstaben spielen keine Rolle. Es ist auch möglich mehrere Flags zu kombinieren:
sed 's/ROT/blau/ig' foobar
Der Fuchs ist blau und blau sind auch Äpfel.
Manchmal möchte man aber auch Pfadangaben ersetzen. Blöd nur, dass der Slash / normalerweise das Muster vom Ersetzungstext trennt. Möchte man nun z.B.
/usr/local/share/foobar durch /usr/share/foobar ersetzen, müßte man sowas nutzen:
sed 's/\/usr\/local\/share\/foobar/\/usr\/share\/foobar/g script
Daher erlaubt es sed, irgendeinen anderen Delimiter zu nutzen, z.B. die Pipe |:
sed 's|/usr/local/share/foobar|/usr/share/foobar|g script
oder den Unterstrich _
sed 's_/usr/local/share/foobar_/usr/share/foobar_g script
oder irgend ein anderes Zeichen, was nicht im Muster vorkommt.
Manchmal möchte man auch das gefundene Pattern im Ersetzungsteil wieder verwenden. Wenn man zum Beispiel eine Anweisung in einer Konfigurationsdatei auskommentieren möchte, die mit "foobar" anfängt kann man das so machen:
sed 's/^\(foobar\)/#\1/' config
#foobar wichtig!
Oder man benutzt einfach den Replacement Character &, der für das Muster steht, das gefunden wurde:
sed 's/^\(foobar\)/#&/' config
#foobar wichtig!
Vereinfachen kann man das noch so:
sed '/^foobar/s/^/#/' config
#foobar wichtig!
Hier benutzen wir den regulären Ausdruck /^foobar/ als Adresse und nur Zeilen, die auf dieses Muster passen, werden ersetzt. Vereinfacht ersetzen wir das Zeichen '^' (das für den Zeilenanfang steht) durch ein '#' und fügen somit eine Raute am Anfang der Zeile ein.
Man kann noch mehr mit regulären Ausdrücken machen. Zum Beispiel alle Großbuchstaben durch ihre Kleinbuchstaben ersetzen:
ls /home/ | sed 's/[[:lower:]]/\U&/g'
CB
CHRISBRA
FTP
Sed sucht nach der Posix-Klasse von Kleinbuchstaben und ersetzt diese durch die entsprechenden Großbuchstaben. Das \U steht für Uppercase und wandelt alle Zeichen in die passenden Großbuchstaben um. Man beachte die Nutzung von & um das gefundene Muster wiederzuverwenden. Ohne das Flag 'g' wäre übrigens nur der erste Buchstabe groß geschrieben worden. Das gleiche kann man übrigens mit dem Kommando y/ erreichen:
ls /home/ | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'
CB
CHRISBRA
FTP
Das ist etwas umständlich, denn das y-Kommando scheint keine Characterklassen anzunehmen, sondern man muß explizit alle Zeichen hinschreiben.
Das war das Wichtigste zum Substitute Kommando. Der nächste Teil kommt bestimmt
Thursday, 7. May 2009
Regexes bei Informatica
Monday, 27. April 2009
Fetchmail SSL-Fingerprint erneuern
13589:error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed:s3_clnt.c:951:
fetchmail: SSL connection failed.
fetchmail: socket error while fetching from ...@gmx.de@pop.gmx.net
fetchmail: Query status=2 (SOCKET)
Man muß dazu sagen, dass ich fetchmail mit der folgenden Konfiguration aufrufe:
user "user@gmx.de" password "passwort" is "user" ssl
sslproto tls1 sslcertpath /etc/ssl/certs sslfingerprint
"BA:03:AC:50:A9:A0:C7:AF:1E:79:3A:B7:C0:E7:19:5E" sslcertck keep
(Nein, das Passwort ist nicht passwort und die E-Mail Adresse ist auch nicht user@gmx.de
In dieser Konfiguration überprüft fetchmail den angegebenen SSL Fingerprint (Option sslfingerprint) gegen den Fingerprint des Zertifikats, dass der Server angibt und wenn der Fingerprint nicht stimmt, dann gibt es eben obige Fehlermeldung. Zusätzlich wird mit der Option sslcertck überprüft, ob das Zertifikat (direkt oder indirekt) vertrauenswürdig ist. GMX verwendet zum Beispiel ein Zertifikat das von Thawte ausgestellt ist. Wenn man das Paket ca-certificates installiert, bekommt man unter anderem das Thawte Root-Zertifikat installiert und das System betrachtet diese Zertifikate als vertrauenswürdig. Der generische, manuelle Weg diese Zertifikate zu erhalten ist für Thawte hier beschrieben.
Zurück zu der obigen Fehlermeldung. Die sieht verdächtig nach einem erneuerten Zertifikat aus. Glücklicherweise kann man das recht einfach prüfen und damit ich mir die passenden Optionen nicht jedesmal aus der Manpage raussuchen muß, hier die Schrittfolge in Kurzform:
notBefore=Apr 27 08:51:09 2009 GMT
notAfter=May 10 07:06:14 2010 GMT
MD5 Fingerprint=92:C8:49:13:3A:55:D6:57:37:5F:0F:12:83:39:CE:06
In Langform: Zunächst bauen wir uns eine verschlüsselte Verbindung zu pop.gmx.net auf. Da sieht man z.B. welches Zertifikat der Server dem Client präsentiert. Dieses Zertifikat kann man sich dann auch in Textform ausgeben lassen (openssl x509 -text
fetchmail: 6.3.9-rc2 fragt pop.gmx.net ab (Protokoll POP3) um Mo 27 Apr 2009 21:43:53 CEST: Abfrage gestartet
Versuche, mit 213.165.64.22/995 zu verbinden...verbunden.
fetchmail: Herausgeber-Organisation: Thawte Consulting cc
fetchmail: Herausgeber-CommonName: Thawte Premium Server CA
fetchmail: Server-CommonName: pop.gmx.net
fetchmail: pop.gmx.net-Schlüssel-Fingerabdruck: 92:C8:49:13:3A:55:D6:57:37:5F:0F:12:83:39:CE:06
fetchmail: pop.gmx.net-Fingerabdrücke stimmen überein.
fetchmail: POP3< +OK GMX POP3 StreamProxy ready
fetchmail: POP3> CAPA
fetchmail: POP3< +OK
fetchmail: POP3< STLS
....
Ach ja, und spätestens am 10. Mai 2010 wird es wieder ein neues Zertifikat geben.
Debugging mit Informatica Powercenter 8
In den letzten 2 Wochen habe ich 2 komplexere Probleme in 2 Flows untersucht. Das Killerfeature was dabei immer genannt wird ist der eingebaute Debugger. Damit kann man einem Datensatz zusehen, wie die Transformationslogik angewandt wird. So richtig schön grafisch und mit Breakpoints. Zumindest theoretisch. Praktischerweise funktioniert das Teil nämlich nicht verläßlich, zumindest, wenn in der Mappinglogik ein Outer-Join enthalten ist. Dann beendet sich der Debugger nämlich einfach ohne ersichtlichen Grund. Wenn man Glück hat, kann man wenigstens noch durch einen Teil der Logik durchsteppen. Was hab ich geflucht, aufgrund dieses Bugs, der schon mindestens seit Version 7 drin ist.
Man kann in diesem Fall also nicht mit dem Debugger debuggen. Was macht man? Richtig, wie früher in der guten alten Zeit(™) das Loglevel hochdrehen auf "Verbose Data" (damit loggt Informatica praktisch für jede Transformation den eingehenden und ausgehenden Datensatz) und dann Logfiles lesen. Lustigerweise hat Informatica mit Version 8 auf eine Art binäres Logfile umgestellt. Man kann diese Dinger nicht mehr anständig mit einem stinknormalen Editor oder Pager lesen, sondern muß den eingebauten Logfile Viewer nutzen. Der ist schon umständlich genug zu nutzen, nur leider ist das Teil auch nicht mal richtig stabil. Während ich also das Loglevel auf Verbose Data hochdrehte und mit ein paar Testdatensatz den ganzen Flow nochmal laufen lies, stellte ich fest, dass das Logfile auf enorme 2 GB angewachsen war. Und das mit nur einer Handvoll Testdatensätze. Aber wartet, es kommt noch besser: Als ich versuchte, das Logfile mit dem eingebauten Logfileviewer zu öffen, ist mit der Viewer gnadenlos abgestürzt. Also Loglevel wieder runtergedreht auf Normal und nur bei vereinzelten Transformationen "Verbose Data" angeschaltet. Danach war das Logfile immer noch mehrere Hundert MB groß, doch zumindest konnte man es betrachten.
Ich glaube jedes Problem hat ca: 1 Arbeitstag gekostet, bis ich den Fehler gefunden hatte. Da gibt es noch Verbesserungspotential.
Friday, 24. April 2009
Restore eines Backups
Diese Woche hatte ich sozusagen den Ernstfall. Ich wollte meine Daten auf eine neue Maschine syncen. Nachdem ich mittels Truecrypt die Partition entschlüsselt hatte brach das Kopieren immer mit einem "Acces Denied" Fehler ab.
Zunächst dachte, das wären Anzeichen für den baldigen bevorstehenden Tod meiner Festplatte. Leicht beunruhigt ließ ich einen Dateisystemcheck laufen, der aber keine Ergebnisse brachte. Testweise an mein altes Arbeitsgerät angeschlossen und siehe da, alles funktioniert wie zuvor. Das machte mich stutzig und nach kurzem Nachdenken kam ich auch auf die Lösung: Das Backup erfolgt aus mehreren Gründen auf ein NTFS-Dateisystem (u.a. Unterstüzung für Dateien größer > 4 GB, nicht so starke Fragmentierung und eben auch Zugriffsberechtigungen). Und da haben wir auch schon das Problem: die ACLs, denn der Inhaber/Owner der Dateien war auf dem neuen System ein anderer (obwohl der Username jedesmal der selbe war).
Leider brachte Google zum Ändern nur die Hinweise: rechter Mausklick auf Datei, Menüpunkt Properties und dann im Reiter Security kann man die Berechtigungen anpassen. Nur, auf dem neuen System gab es den Menüpunkt nicht. Den gibt es nämlich nur, wenn man "Use Simple File Sharing (Recommended)" nicht angehakt hat (Explorer, Menü Tools->Folder Options, Reiter View, letzter Punkt). Nach dem ich den Haken entfernt hatte, gab es auch den Reiter Security in den Eigenschaften einer Datei.
Also in die Eigenschaften der Ordner gegangen, Reiter Security, den Advanced Knopf ausgewählt und nun einmal im Reiter Permissions dem neuen Benutzer explizit alle Rechte geben und zusätzlich im Reiter den Owner auf den neuen alten Nutzer gesetzt und nicht vergessen das Häkchen "Replace permission entries on all child objects." bei Permissions anhaken und im Reiter Owner das Häkchen "Replace Owner on subcontainers and objects" anhaken. Damit die Änderungen auch in allen Unterobjekten übernommen werden.
Danach ok anklicken und Windows rattert über die komplette Backup Platte und ändert alles wie gewünscht.
Tuesday, 24. March 2009
Eine kleine Einführung in sed, Teil 1
Sed ist die Abkürzung für Stream Editor, was soviel bedeutet wie dass es sich um einen nicht interaktiven Editor handelt, der somit für Batchverarbeitung sehr gut geeignet ist.
Während man bei einem interaktiven Editor typischerweise den Cursor bewegt und dann an bestimmten Stellen auf dem Monitor Veränderungen vornimmt, arbeitet man bei Sed in Ermangelung eines Cursors mit Aktionen, die typischerweise durch Muster oder Zeilennummern spezifiziert werden. Das klingt im ersten Moment etwas seltsam, aber man kann damit sehr flexibel mit einem einzelnen Einzeiler Muster verarbeiten. Das heißt, sed liest die zu bearbeitende Datei normalerweise zeilenweise ein, kopiert jede Zeile in einen Puffer (den Pattern-Space) und gibt die Veränderungen, so es welche gab - wieder aus.
So kann man zum Beispiel einfach in einem Input alle Vorkommen von dem falschen englischen Artikel teh durch die korrekte Version the ersetzen. Oder man kann alle Kommentarzeichen aus einer Konfigurationsdatei entfernen. Verrücktere Leute als ich, die sich wirklich mit sed auskennen, haben bereits Spiele in sed programmiert, einen Debugger implementiert, einen minimalistischen Webserver erstellt und wahrscheinlich noch einen Haufen anderer verrückter Dinge angestellt, von denen ich nichts weiß.
Dies alles, obwohl die Sprache keine Variablen kennt und nur eingeschränkte Kontrollstrukturen. Seine Sprachelemente erscheinen auf den ersten Blick etwas kryptisch und sehen oft auch aus wie Buchstabensalat. Es hat wie so viele praktische Tools seinen Ursprung in der Unix Welt und wurde 1973 oder 1974 entwickelt (Unix Version 4) als Erweiterung bzw. Nachfolger von grep und ed. Die verwendete Syntax und Lexik beeinflußte auch maßgeblich Programme wie vi, perl, awk und vermutlich auch die ein oder andere Shell.
Da sed daher so weit verbreitet ist, gehört es auch zum Single Unix Specification, welches u.a. Schnittstellen und typische Utilities definiert, die auf einem System vorhanden sein müssen, um sich Unix nennen zu dürfen. Damit ist der grundsätzliche Befehlsatz und die Grammatik von sed, die man erwarten kann auch schon standardisiert.
Ich denke, damit hab ich kurz das Wichtigste beschrieben, um zu verstehen worum es eigentlich geht. Fortsetzung folgt.
Tuesday, 11. November 2008
Die Sache mit gelöschten Dateien...
Ein verdächtiger Hinweis auf so eine Situation ist, wenn die Abweichung zwischen du und df groß ist. Das passiert, weil kein Hardlink mehr auf die gelöschte Datei in irgendeinem Verzeichnis mehr vorhanden ist (Linkcount ist 0, Datei ist als gelöscht markiert im Dateisystem) und daher von du nicht bemerkt wird. Im Dateisystem gibt es die Datei aber noch, daher kommt die Abweichung von df.
logrotate ist so ein Kandidat für solche Geschichten, wenn das Logfile zwar wegrotiert wird, aber hinterher der loggende Prozess nicht neu gestartet wird. Dieser Prozess wird dann fröhlich weiter einen Filedescriptor beschreiben, bis er irgendwann mal beendet wird.
Finden kann man solche Prozesse zum Beispiel mit find:
t41:~$ find -L /proc/*/fd -xdev -type f -links 0 2>/dev/null
/proc/4695/fd/5
/proc/self/fd/3/5
t41:~$
Den zweiten Prozess kann man ignorieren.
Mal sehen welcher Prozess sich hinter dem ersten Prozess versteckt:
t41:~$ cat /proc/4695/cmdline; echo
mutt
~$
Ah ja. Ein cat /proc/4695/fd/5 gibt auch den Inhalt aus, es ist eine Mail, die ich gerade gelesen habe.
Mit lsof geht das ganze noch einfacher:
t41:~ [1128]# lsof +L1
COMMAND PID USER FD TYPE DEVICE SIZE NLINK NODE NAME
dhclient3 2239 root txt REG 8,1 363232 0 81742 /sbin/dhclient3
smbd 5822 root 2w REG 8,1 863 0 434171 /var/log/samba/log.smbd.1 (deleted)
smbd 5822 root 7w REG 8,1 863 0 434171 /var/log/samba/log.smbd.1 (deleted)
tail 11182 chrisbra 3r REG 8,1 104909 0 401728 /var/log/syslog.1 (deleted)
Die erste Datei ist ein Fehlalarm. Warum dort bei diesem Filedescriptor ein Linkcount von 0 angezeigt wird, verstehe ich gerade nicht. Die richtigen sind die, wo (deleted) steht.
Hm mal sehen, was wir da noch so rausfinden können:
t41:~ [1130:1]#lsof +L1 -Fnskc |awk '
/^s/ {
j=gensub(/^s/, "",1,$1)
}
/^n/ && /(deleted)/ {
i=gensub(/^n/, "",1,$1)
a[i]=j;
}
END {
for (i in a) {
s+=a[i];
print "Files: ", i , " Size: " , a[i];
}
u="B"
if (s>=1024) {
s/=1024
u="kB"};
printf("-------------------\nTotal:\t%.2f %s\nAvg:\t%.2f %s\n", s, u, s/length(a),u);
}'
Files: /var/log/samba/log.smbd.1 Size: 863
Files: /var/log/syslog.1 Size: 104909
-------------------
Total: 103,29 kB
Avg: 51,65 kB
Die 2 Prozesse verbrauchen also ca: 103 kB mehr an Platz. Ein Restart sollte reichen, um den Platz wieder freizugegeben.
Falls das aus irgendeinem Grund nicht geht, weil man die Prozesse nicht restarten kann, aber trotzdem kein Wert auf die Daten in den gelöschten Dateien legt, müßte man die Daten ungefähr folgendermaßen freigeben können:
t41:~ [1155]# for i in 5822 11182;
do find -L /proc/$i/fd -type f -links 0 -exec sh -c 'exec > {}' \; ; done
t41:~ [1156]# lsof +L1 -Fnskc |awk '
/^s/ {
j=gensub(/^s/, "",1,$1)
}
/^n/ && /(deleted)/ {
i=gensub(/^n/, "",1,$1)
a[i]=j;
}
END {
for (i in a) {
s+=a[i];
print "Files: ", i , " Size: " , a[i];
}
u="B"
if (s>=1024) {
s/=1024
u="kB"};
printf("-------------------\nTotal:\t%.2f %s\nAvg:\t%.2f %s\n", s, u, s/length(a),u);
}'
Files: /var/log/samba/log.smbd.1 Size: 0
Files: /var/log/syslog.1 Size: 0
-------------------
Total: 0,00 B
Avg: 0,00 B
Zunächst wurden mit einer Schleife alle Filedescriptoren gefunden, die zu den beiden Prozessen gehören und einen Linkcount von 0 hatten. Diese Filedescriptoren wurden einfach noch einmal durch die Shell zum Schreiben geöffnet und praktischerweise löscht die Shell dabei gleich den vorhandenen Inhalt.
Wie man anhand des zweiten mini-Scripts sieht, sind jetzt zwar immernoch 2 Prozesse vorhanden, die auf gelöschte Dateien zugreifen möchten, aber diese Dateien nehmen keinen Platz mehr weg.
Empfehlen tu ich diesen Weg aber nicht. Ich denke, dabei könnten einige Prozesse drüber stolpern. Es ist also mehr oder weniger nur ein übler Hack.
Einen Vorteil hat das Ganze übrigens auch. Versehentlich gelöschte Dateien können so schnell und einfach wieder hergestellt werden, so lange noch ein Prozess diese Dateien geöffnet hält. Ein cat /proc/5822/fd/2 > /var/log/smbd.log und schon ist die Datei wieder im Dateisystem. Funktioniert nur leider nicht mehr, wenn man die Datei schon geleert hat, wie gerade eben durch das letzte find-Statement geschehen. ;(
