Unix: Dateien mit nicht druckbaren Zeichen

Ich hatte gerade ein Verzeichnis auf einem Solaris 10 System, welches eine Datei mit dem Namen ¨ beinhaltete. Meistens sind solche Dateien Überbleibsel von wilden Kommandozeilen Orgien, bei denen irgend eine Umleitung schief gelaufen ist. Irgend ein Sonderzeichen hat sich dann im Dateinamen verewigt.

Doch wie schaut man solch eine Datei an (um entscheiden zu können, dass diese wirklich weg kann?) und wie löscht man diese dann?

Am einfachsten geht das wohl, wenn man statt über den Dateinamen über die Inode Nummer geht. (Eine Inode ist ein Eintrag in einem Unix-Dateisystem, der Metadaten einer Datei enthält.)

# ls -alFi
385683 drwxr-xr-x   8 pcs      iccc         512 Oct 29 11:59 ./
338148 drwxr-xr-x  23 root     root         512 Oct 13 12:55 ../
461707 drwxrwsr-x   2 root     iccc         512 Oct 13 12:54 tmp/
386788 -rw-r–r–   1 root     root        7694 Sep  1 08:31 ¨

Nun hat man aber immer noch das Problem, dass z.B. ein cat oder ein rm die Datei nicht behandeln können, da diese Programme nicht mit der Inode umgehen können. Hier hilft find, welcher gezielt nach Inodes suchen kann und dabei den korrekten Dateinamen mittels exec an ein anderes Programm übergeben kann.

Einige Beispiele

# Die Datei umbenennen in foobar
find . -inum 386788 -exec mv {} foobar \;

# Datei anschauen mit less
find . -inum 386788 -exec less {} \;

# Datei direkt löschen
find . -inum 386788 -exec rm {} \;




Solaris 10: Zone im ‹mounted› Status

Eine Zone, welche sich im Status mounted befindet? Das kann eigentlich nicht sein.  Zumal es diesen Status in den offiziellen Dokumentationen von SUN auch nicht zu geben scheint.

# zoneadm list -cv
  ID NAME          STATUS     PATH                     BRAND    IP
   0 global        running    /                        native   shared
   1 zone1         running    /opt/local/zones/zone1   native   shared
   2 zone2         running    /opt/local/zones/zone2   native   shared
  10 zone3         mounted    /opt/local/zones/zone3   native   shared

Durchkämmt man den OpenSolaris Code nach den verschiedenen Statussen findet man jedoch auch die Definition für den mounted Status

#define ZONE_STATE_MOUNTED

Und wie kommt dieser Status zustande? Hauptsächlich durch die Installation eines neuen Patches/Paketes. Hierdurch wird mit den Befehlen die Zone (sofern diese nicht lief) in den Status mounted gebootet um dann das Pake/den Patch installieren zu können. Im Normalfall wird das entsprechende Tool dann auch den Ursprünglichen Zustand wieder herstellen. Aber manchmal funktioniert das halt nicht.

Das Problem ist, dass man mit der Zone solange nichts machen kann (kein reboot, kein halt) bis man den Status auf installed gebracht hat. Hierzu verwendet man einen ebenfalls eine nicht angegebene Option von zoneadm: unmount

Mit dem Befehl:

zoneadm -z zone3 unmount

Wird die Zone sauber unmounted und wieder in den Status installed gebracht.




/bin/tar: Argument list too long

Wo sind bloss die 50GB Speicherplatz geblieben?

Diese Frage musste ich mir heute Morgen auf einem unserer Solaris 8 Systeme stellen. Nach einigen Aufräumarbeiten war der Übeltäter gefunden. Eines unserer Projektverzeichnisse hatte Logdateien enthalten, welche 38GB gefressen hatten.

Das Problem: Mir konnte natürlich wiedermal niemand sagen ob die Daten noch gebraucht werden.

Also wollte ich all die Dateien mit gtar/bzip2 Archivieren. Doch da hatte ich die Rechnung ohne den Wirt gemacht. Ein gtar cvjpf Archivdatei.tar.bz2 logfiles* scheiterte an der Menge der übergebenen Dateien und beendete sich mit der Fehlermeldung:

/bin/tar: Argument list too long

Was? Wieviele Datein waren denn da auf dem Server? Ein ls -1|wc -l brachte mir die Gewissheit.

372’378 Dateien!

Das ist natürlich eine Menge. Und wie sichere ich die nun? Ganz einfach. Zuerst wird mittels find eine Liste aller Dateien erstellt und danach wird das tar File anhand dieser Datei erzeugt.

find . -name '*.log' -print >/tmp/archivliste
tar cvjpf logfiles.tar.bz2 --files-from /tmp/archivliste

So einfach kann es sein… 🙂

Nachtrag:

Will man die Dateien löschen, hat man mit rm natürlich wieder das selbe Problem. Aus diesem Grund hier der Befehl, wie die Dateien löschen kann.

find . -name '*.log' | xargs rm

Uebrigens:

Der Grund, warum es über die Argumente nicht geht ist die beschränkte Puffergrösse für Argumente. Denn ein logfiles* wird in logfiles1 logfiles2 logfiles3 etc. aufgeschlüsselt. Und bei knapp 380’000 Daeien ist dieser Pufferplatz schnell einmal voll. Zumal der Puffer wohl nur zwischen 32Kb und 64Kb gross sein wird.




Solaris 10: Kernel Modul Parameter setzen

Gerade eben wollte ich auf einem unserer Solaris 10 Systeme den Parameter nfs_portmon des nfssrv Modules von 1 auf 0 setzen, damit er die unprivilegierten Ports nicht prüft.

Nun wird überall im Netz geraten, in /etc/system den Eintrag vorzunehmen und dann einen reboot durchzuführen. Warum aber sollte ich ein ganzes System mit unzähligen Zonen neu starten, wenn ich doch nur einen Parameter ändern möchte?

Es muss doch bei Solaris 10 möglich sein, wie unter Linux (mit dem sysctl Befehl) die Kernelkonfiguration zu manipulieren. Nach ein wenig suchen fand ich denn auch die Lösung. mdb

# mdb -kw
Loading modules: [ unix krtld genunix specfs dtrace cpu.generic ...etc...
> nfs_portmon/D
nfs_portmon:
nfs_portmon:    1
> nfs_portmon/W 0
nfs_portmon:    0x1             =       0x0
> nfs_portmon/D
nfs_portmon:
nfs_portmon:    0
> $q

Mdb ist der modulare debugger von Sun. Man startet ihn mit den Parametern -kw, welche auf die Objektdatei /dev/ksyms und das Core File /dev/kmem schreibend zugreifen.

Nun kann man im Debugger einfach den Parameter (ohne Angabe des Modules, da dies automatisch aufgeschlüsselt wird) gefolgt von einem /D für dump oder einem /W <wert> für write angegeben werden.

Um den Debugger zu beenden, gibt man $q ein.

So einfach geht das 🙂 (und erst noch ohne rebooot!).




Solaris 10: Ohne Default Route, kein Ping

Folgende Situation:

Ein Rechner hat Zwei Netzwerkinterfaces e1000g0 und e1000g1. Jedes dieser Interfaces ist in einem unterschiedlichen Netz. Sagen wir einmal e1000g0:192.168. 1.0 und e1000g1:192.168.2.0.

Richtet man nun Zone A mit einem virtuellen Interface e1000g0:1 ein und eine Zone B mit dem virtuellen Interface e1000g1:1 dann können sich die beiden Zonen gegenseitig nicht anpingen.

Eigentlich ist das auch ganz logisch, denn beide Zonen wissen nichts von einander. Um das Problem zu lösen muss man lediglich sicherstellen, dass für beide Netze eine defaultroute in der globalen Zone gesetzt ist.

Wichtig! Als default Gateway darf NICHT die IP Adresse des globalen Interfaces dienen, da der Solaris Kernel die Pakete anscheinend verwirft. Weiterhin muss man sicherstellen, dass an dieser Adresse kein Gerät angeschlossen ist (ausser es handelt sich um einen «echten» Gateway).




Solaris Thermal Zone Monitor deaktivieren

Das Logfile wurde gröser und grösser (ACPI Thermal Zone Fehlermeldungen). Schuld war wieder einmal das ACPI. Genauer die Thermische Zonen Spezifikation eines x86 Rechners.

Da es sich bei dem Gerät aber um ein lüfterloses System handelt ist diese Option sowieso obsolete. Daher gehört dieses auch deaktiviert. Aber wie?

Schuld für die Meldung ist tzmon. Ein Pseudo Kernel Modul, welches ständig die Temperaturwerte abfragt und im Falle eines Fehlers Alarm schlägt. Das funktioniert solange gut, wie er die Werte auch auslesen kann. Bei mir ging das nicht.

Um den Treiber zu deaktivieren muss man lediglich in /etc/system die folgende Zeile einfügen:

exclude: tzmon




Solaris Default Postscript Drucker einrichten.

Man kann entweder in /etc/printers.conf (sofern man kein NIS oder LDAP verwendet) die Informationen von Hand eintragen (was aber meistens Fehlerbehaftet ist) oder man fügt die Informationen mit lpset ein.

Da heutige Postscript Drucker in der Regel einen eigenen Printserver am laufen haben ist die Handhabung spielend einfach. Die Option -n gibt an, dass /etc/printers.conf und nicht etwa NIS oder LDAP verwendet werden soll und die Option -a bsdadd=server,destination,Solaris gibt an wo sich der Printserver befindet, welcher Spool verwendet werden soll und Solaris, dass eine Solaris Printserver Erweiterung verwendet werden soll.

 lpset -n system -a bsdaddr=myprinter,lp,Solaris myprinter

Somit wurde der Drucker myprinter eingerichtet. Um diesen nun als Standarddrucker verwenden zu können nutz man folgenden Befehl:

lpset -n system -a use=myprinter _default