core file handling unter Ubuntu

Wer sich als SW Entwickler auf einer Ubuntu LTS Plattform wundert, wo den die core files geblieben sind, welche das OS erstellt wenn Programme bestimmte Signale (SIGSEGV,SIGABRT,SIGQUIT,….) empfangen, der sollte mal den Inhalt von

/proc/sys/kernel/core_pattern

anschauen. Der Inhalt

|/usr/share/apport/apport %p %s %c

mit dem einleitenden pipe character, legt fest das entstehende core files direkt als stdin stream dem frontend Programm apport zur Verfügung stehen. Auf der Ubuntu Wiki Seite über das Programm apport ist erklärt, wie das Programm die core Informationen dem User präsentiert. Das Programm führt unter

/var/log/apport.log

alle events. Dort klärt sich auf das Phänomen auf, das core’s von bestimmten Programmen (z.B. im Home-Bereich) ignoriert werden. Prinzipiell werden nur core’s von packetierten Programme oder von Launchpad Applikationen ausgewertete und somit unter /var/crash abgelegt.

Bei eigenen Programmen gibt es die Möglichkeit die Einstellungen von apport in

/etc/apport/crashdb.conf

mit bspw. hooks zu erweitern, oder das Program unterhalb der /opt Struktur abzulegen. Eine Diskussion über das Thema in Bezug auf eigene Programme findet man auf dieser askubuntu Seite.
Die von apport mit weiteren Informationen angereicherten core files, werden zu sog. crash files unterhalb von /var/crash, welche bspw. mit dem Programm apport-retrace untersucht werden können (backtraces ,etc..)

Downgrade eines SW Pakets unter Ubuntu

Ein Downgrade eines Paketes unter Ubuntu geht prinzipiell sehr einfach. Der Befehl

sudo apt-get install <PACKAGE>=<VERSION>

würde das Paket auf die gewünschte downgraden. Die Frage ist allerdings wie genau die Version heisst und ob sie überhaupt noch von den offiziellen Servern bereitgestellt wird.
Um das herauzubekommen wird der Befehl

apt-cache show <PACKAGE>

ausgeführt. Dieser zeigt blockweise die verfügbaren Versionen auf – der Versionsstring ist daher eher opulent, bspw. Version: 4.9.1.1-1ubuntu0.1
Falls sich die gewünschte Version hier allerdings nicht mehr befindet, so kommt man um ein manuelles de- und reinstallieren des/der Paket(e) nicht herum.

UTF-8 Dateinamen: Linux vs. Mac OS X (Stand 2014)

Wie schon vor 8 Jahren beschrieben gibt es auch heute immer noch Probleme beim Austausch von Dateien, deren Dateinamen Buchstaben jenseits des ASCII Zeichensatzes beinhalten.

Die Situation hat sich bis heute in 2 Punkten geändert.

  1. die UTF-8 Form D unterstützung in Linux ist beinahe perfekt. Die Dateimanager zeigen die Dateien mit den zusammengesetzen Buchstaben richtig an
  2. Mac OS X Mavericks geht jetzt bei NFS mounts davon aus, dass die Dateinamen Form C dekodiert sind (was bei Linux NFS Server ja richtig ist).

Leider gibt es immer noch eine Menge Lücken, bspw. der Austausch von ext3 Datenträgern zu Mac OS X via Paragon ExtFS for Mac OS X, welches keine Konvertierung vornimmt und daher Form C Dateien direkt an Mac OS X weitergibt, deren Programme dann mit diesen Dateien nicht umgehen können.

Einfügen einer Bytesequenz mittels hex-Editoren

Die Aufgabe lautet die UTF-8 BOM (0xEFBBBF) mittels eines Hexeditors in ein simples Textfile einzufügen.
Getestet wurden auf Ubuntu 12.04 verschiedene Tools – hier das Ergebnis:

1. hte (Konsolenhexeditor mit ncurses)

Leider ist die Integration von ncurses in die Ubuntu Welt – genauer gesagt in ein Gnome Terminal – nicht prickeld. Wesentliche Kommandos die mit der ALT Taste gesteuert werden wurden anstatt in das ncurses Programm an das darüberliegende Terminal übertragen, so dass ich es nicht schaffen konnte in den Edit Mode zu kommen. Ansonsten ist die grafische Representation des Byte-Codes ansprechend.

2. vi (mittels xxd)

Falls man mit vi -b ein File im binären Modus öffnet, kann man mit folgender Sequenz
:%!xxd
..Manipulation des Files
:%!xxd -r
die Datei ändern. Das Hinzufügen oder Entfernen von Bytes gelang mir auf Anhieb nicht. Mein Fazit: Für schnelle Manipulationen ideal, aber nur dafür.

3. okteta

Der KDE Hexeditor läuft selbstverständlich auch auf dem Ubuntu Unity Desktop. Was die Optionen der grafischen Representation anbelangt das beste Programm. Im Detail offenbaren sich – wie so oft unter KDE Schwächen. Bei der Characterdarstellung der Bytes sollte man sich auf einen rein lokalen 8-Byte Zeichensatz beschränken anstatt dem User vorzugauckeln, dass ein Byte eines Umlautes unter UTF-8 einem Character entspricht (bei der Byte-Sequenz C3B6 ‚ö‘ wird schon alleine C3 unter UTF-8 als ‚ö‘ dargestellt, zumindest in der Decoding Tabelle). Auch die Layout-Voreinstellungen der GUI sind nicht optimal.

4. bless

Das Mono-basierte Programm hat leider die Systembedingten Abhängigkeiten von allerhand Mono-Libraries.
Ansonsten wirkt das Programm aber sehr aufgeräumt und stringent. Von der Bedienung her das einfachste Programm – allerdings kann es nach der Manipulation nicht auf das geöffnete File zurückschreiben. Wer das versucht, bekommt folgende kryptische Fehlermeldung.
blessSaving

Fazit: Je nach Geschmack eignet sich okteta oder bless am Besten für diese Aufgabe

Immutable Files auf Linux

Wenn sich ein File auf einem Linux System nicht mal mit Hilfe eines root-accounts löschen lässt, dann sollte man mal die sog. I-node flags (Extended Filesystem Attributes) genauer anschauen. Der Befehl dazu lautet

lsattr <FILE>

Falls in der Ausgabe der Character i vorkommt, dann ist das sog. FS_IMMUTABLE_FL flag gesetzt worden, welches eine Modifikation des i-Nodes gänzlich unterbindet (d.h. weder inhaltliche Veränderung noch eine Änderung von Metadaten ist erlaubt).
Ein Setzen des Flags mit

chattr +i <FILE>

erfordert die CAP_LINUX_IMMUTABLE capability. Programmatisch erfolgt dieselbe Operation mit ioctl

if (ioctl(fd,FS_IOC_GETFLAGS,&attributes)==-1) errExit("fetching attributes");
attributes |= FS_IMMUTABLE_FL;
if (ioctl(fd,FS_IOC_SETFLAGS,&attr) == -1) errExit("setting attributes");

Dieses i-node flag ist unter Linux seit Kernel 2.6.19 Filesystem-übergreifend implementiert. Es kann bspw. zum temporären Schutz von Dateien in Systemverzeichnissen genutzt werden, aber auch von Rootkits die Schadsoftware ins System eingeschleust haben.

Punkt oder Komma

Wenn ein Program dass Gleitkommazahlen von einer oder in eine Textdatei liest, bzw. schreibt nicht mehr funktioniert, dann sollte man sich genauer mit LC_NUMERIC befassen. Dieser Artikel behandelt die Auswirkungen auf Qt- und reine C-Programme.

LC_NUMERIC ist Bestandteil der sogenannte locales, der Lokalisierungen (oder auch Regionalisierungen) auf einem System. Diese Lokalisierungen lassen sich sehr fein einstellen – bspw. LC_MONETARY für die Währung oder eben LC_NUMERIC für das Zahlenformat – aber auch zusammenfassend mittels LC_ALL. Setzt man bspw. LC_ALL=de_CH.UTF-8, dann wird diese Einstellung auf alle sublocales übertragen und für LC_MONETARY ist der Franken gesetzt, wenn auch das meiste andere ziemlich deutsch ist.

Ok, nun aber zum Zahlenformat – und um die Sache ein bischen zu beschleunigen, soll eine Textdatei mit folgendem Inhalt ausgelesen werden.

#Hallöle
33.456,78
33456.78
33,456.78
33,99
33.98
33.777

Um die Zahlen besser zu verstehen muss noch einmal ausgeholt werden. LC_NUMERIC legt zwei Parameter fest.
Den Dezimaltrenner und den Tausender-Trenner. Er wird folgendermassen gesetzt:

Locale Dezimaltrenner Tausender-Trenner
en_US . ,
de_DE , .
C .

Das bedeutet, dass die deutsche Lokalisiserung genau andersherum als die US-Amerikanische ist. Die sog. C-Locale (auch POSIX-Locale genannt) kennt nur den Dezimaltrenner. Diese Locale ist als Rückfallebene gedacht.

Wie verhält sich nun ein Qt-Programm (Qt4), dass die o.g. Textdatei zeilenweise einliest und versucht den Text in Zahlen zu konvertieren? Zuerst einmal wird ein Testprogram unter der Umgebung LC_NUMERIC=de_DE.UTF-8 gestartet.

localeTest_de

Die Erklärung ist überrasch komplex. Zuerst einmal muss festgestellt werden, dass Qt Programme generell LC_NUMERIC-aware sind. Dies wird dadurch erreicht, dass QCoreApplication

setlocale(LC_ALL,"");

aufruft und damit locales aus dem Environment dem Programm zur Verfügung gestellt werden (dies wird durch die doppelten Anführungszeichen erreicht). Dennoch werten nicht alle Qt-Methoden LC_NUMERIC aus.

QByteArray::toDouble()
ignoriert die gesetzte locale und benutzt immer die C-Locale.

QString::toDouble()
verhält sich am kompliziertesten. Es wird der Dezimaltrenner der gesetzten locale ausgewertet, nicht aber der Tausender-Trenner (die Gründe liegen in der Kompatibilität zu C, siehe später). Gleichzeitig wird die C-Locale immer als Fallback mitausgewertet. Bei Qt5 verhält sich übrigens QString::toDouble wie QByteArray::toDouble

QLocale::toDouble()
hingegen orientiert sich ausschliesslich an der gesetzten locale.

Zum Vergleich nun die Ausgabe unter dem Environment LC_NUMERIC=en_US.UTF-8

localeTest_en

Interessant ist nun der Vergleich zu reinen C-Programme. Denn reine C-Programme mit ihren typischen Funktionen

printf/fprintf
scanf/fscanf
strtof

..usw. ignorieren standardmässig die gesetzte locale und stützen sich immer auf die C-Locale. Erst durch den schon oben genannten Aufruf von setlocale werden C-Programme locale-aware.
Werden allerdings C-Funktionen – bspw. aus einer Bibliothek – von einem Qt-Programm verwendet, sind sie automatisch locale-aware, da ja wie schon erwähnt QCoreApplication setlocale aufruft.

Dies ist eine große potentielle Fehlerquelle!

Um den Bogen zu QString::toDouble() nochmals zu spannen, sei erwähnt, dass C-Funktionen den Tausender-Trenner standardmässig ignorieren. Um z.B. printf zur Ausgabe des Tausender-Trenners bei Gleitkommazahlen zu zwingen, muss man

printf("Gezwungen zu %'f",myfloat);

einen Abostroph vor dem Formatierungszeichen einführen.
Zum Ausprobieren liegt das Qt Beispielprogramm sowie zwei plain C-Programme im diesem Archiv bei

fair_sched_class und rt_sched_class

Standardprozesse unter Linux werden nun schon seit Kernel 2.6.23 durch den Complete Fair Scheduler verarbeitet, der seinerzeit den O(1) scheduler mit seinen dynamschen Prioritäten beerbte.

In diesem Zusammenhang wurde aber nicht nur der O(1) scheduler durch einen anderen ersetzt. Es wurde vielmehr ein ganzes scheduler Framework erschaffen, bei dem von oben nach unten die scheduler Klassen mit Ihren jeweiligen schedulern abgearbeitet werden. Der simple Ansatz lautet, dass immer versucht wird denjeniegen Prozess zu finden, welcher in der höchstmöglichen Klasse lauffähig (runnable) ist.
Derzeit sieht die scheduler Klassenhierarchie folgendermaßen aus:

  1. stop_sched_class
  2. rt_sched_class
  3. fair_sched_class
  4. idle_sched_class

Die Hintergründe sind im aktualisierten Linux Realtime Dokument zusammengefasst.

MIME Types unter Linux

Die Multipurpose Internet Mail Extensions sind entgegen ihrem Namen auch für die Identifizierung eines Dateityps auf Linux Desktops verantwortlich.

Eine gemeinsame Technik der freedesktop Organisation sorgt dafür, dass ein Verfahren dabei auf allen Desktops‘ – Gnome,KDE,Unity.. – gleichermassen funktioniert. Die gemeinnützige Organisation kümmert sich dabei vor allem um die Standardisierung und stellt teilweise sogar SW (software) bereit.
Eine Übersicht der MIME-Type Spezifikation findet sich hier, während der Ordner mit den letzten verfügbaren Änderungen sich hier befindet.

Wenn man einen oder mehrere neue MIME-Types (mit dazugehörigem Programm) einführen möchte, geht man am besten folgendermaßen vor:

  1. Man sucht sich einen passenden Ablageordner – die auf dem System vorhandenen sind
    $XDG_DATA_DIRS/mime
    $XDG_HOME_DIR/mime

    falls XDG_HOME_DIR nicht gesetzt ist, gilt
    ~/.local/share/mime
    Natürlich kann man bspw. XDG_DATA_DIRS auch erweitern um einen neuen Pfad einzuführen
  2. Eigene MIME-Type Deklarierungen müssen innerhalb einer standardisierten XML-basierenden Datei im Ordner packages (unterhalb des Ordners mime) gespeichert werden, bspw
    ~/.local/share/mime/packages/myType.xml
    Eine xml Datei kann dabei auch mehrere MIME-Types definieren. Der genaue Vorgang erklärt eine hervorragende Tutorialseite auf freedesktop:
    Tutorial: adding MIME information to the database
  3. Die sog. MIME-Type database muss aktualisiert werden. Dazu gibt es ein Skript welches die ganzen im Punkt 1. erwähnten Verzeichnisse durchscannt und dort jeweils dezentral binär aufgebaute Hilfsdateien anlegt. Das shell script welches natürlich mit Administrationsrechten ausgeführt werden muss, lautet
    update-mime-database
  4. Die Verknüpfung eines MIME-Types mit einem Programm ist nicht Sache der MIME-Type Definition. Stattdessen legen die Programmbeschreibungsdateien, die sog. desktop-Dateien, offen welche MIME-Types sie bearbeiten. Diese Dateien mit der Endungs .desktop, liegen in
    XDG_DATA_DIRS/application
    XDG_HOME_DIR/application

    mit denselben Ergänzungen wie im Punkt 1.
    Die freedesktop Spezifikation findet man auf folgender Seite. Ein anschauliches Beispiel findet sich hier.
  5. Nachdem man die MIME-Types und Anwendungen die bestimmte MIME-Types bearbeiten können festgelegt hat bleibt noch folgende Frage zu klären: Welche Anwendung ist die bevorzugte Anwendung eines MIME-Types, bspw. image/png ?
    Dort hat jeder Desktop (bspw. KDE) seine Voreinstellungen in der generierten mime.cache Datei (siehe Punkt 3. – Hilfsdateien) getroffen. Diese Entscheidungen können aber ergänzt oder geändert werden.
    Dazu muss man die Datei
    mimeapps.list
    unterhalb von
    XDG_DATA_DIRS/application
    XDG_HOME_DIR/application

    ändern. Wie genau erklärt die Spezifikation auf freedesktop an dieser Stelle.
    Neben der Angabe einer bevorzugten Anwendung für einen MIME-Type in der Sektion
    [Default Associations]
    gibt es auch noch die Möglichkeit zusätzliche Assoziationen zu kreieren oder zu vorhandene zu löschen.

  6. Am Ende bleibt noch die Frage wie man an diese MIME-Type Informationen gelangt? Sicher, haben die grossen Desktops Routinen dafür entwickelt die den Spezifikationen von freedesktop genügen, aber wie kommt man als ISV (Independent Software Vendor) an diese Informationen.
    Vorab – eine API gibt es nicht – unter keiner Sprache. Was es gibt sind Skripte allen voran
    xdg-mime
    des Portland SW Paketes von freedesktop (der SW Part von freedesktop, siehe Einleitung). Unter Ubuntu/Debian gibt es auch noch das Perl-Skript
    mimetype
    mit welchem man wesentlich mehr Informationen abgreifen kann.
    Zu diesem Thema möchte ich noch auf 2 nützliche Links verweisen
    http://wiki.ubuntuusers.de/MIME-Typ
    http://aksubuntu.com/questions/279899

Abschliessend lässt sich sagen, dass die MIME-Type Informationen unter Linux ausgereift und ausreichend ist. Was verbesserungsbedürftig ist, und leider gerade dahindarbt, ist die SW-Unterstützung, v.a. eine C/C++ API seitens freedesktop.org wäre wünschenswert. Dies soll aber nicht darüberhinwegtäuschen, dass die Zusammenarbeit der Linux Desktops gut funktioniert.

gcc: benötigte Bibliotheken nach dem object file

Eine Überraschung erlebte ich beim Bauen einfacher Demonstrationsprogramme unter Ubuntu 12.04. Folgende Anweisung:

gcc -lpthread -o pthread_demo pthread_demo.c

erzeugte beim Linkvorgang mehrere unresolved symbols bzgl. pthread Methoden. Tatsächlich wurde aber mit gleicher Anweisung das Programm zu den Anfangszeiten von Ubuntu 12.04 gebaut. Eine Umstellung des Linker Programms ld bzw. der Aufruf desjeniegen durch gcc dürfte daran schuld sein. In ld Version 2.20 führt der Linker-Flag

--as-needed

dazu, dass Bibliotheken nur noch gelinkt werden wenn diese undefined Symbols im Objekt File oder einer zuvor gelinkten Bibliothek auflösen kann. Daher muß von nun an das Objekt File vor den benötigten Bibliotheken im gcc Aufruf stehen.

gcc -o pthread_demo pthread_demo.c -lpthread

Alternativ könnte man das alte Verhalten mit folgendem Linker-Flag wiederherstellen

gcc -Wl,--no-as-needed -lpthread -o pthread_demo pthread_demo.c

Libraries Suchpfade (DT_PATH vs. DT_RUNPATH)

Seit geraumer Zeit gilt in der ELF Spezifikation (betrifft Linux) das ELF Symbol DT_RPATH (oder nur rpath) als deprecated, also veraltet. Der Nachfolger ist DT_RUNPATH (oder nur runpath) und wird von den GNU linkern seit langem unterstützt.

Es gibt nur ein entscheidenden Unterschied: Während DT_RPATH zur Laufzeit vor der Umgebungsvariable $LD_LIBRARY_PATH durchsucht wurde, wird DT_RUNPATH erst nach der Umgebungsvariable ausgewertet.

Wenn diese beiden ELF Symbole gleichzeitig vorhanden sind wird DT_RPATH ignoriert. Die gcc Linker Option -Wl,-rpath erzeugt derzeit standardmässig beide, was man aber mit dem Flag –disable-new-dtags ausschalten kann um das alte Verhalten (rpath gewinnt vor $LD_LIBRARY_PATH) zu erzwingen.

Der Grund für diese – zugegeben nicht neue – Änderung besteht wohl darin mehr Druck aufzubauen um zumindest auf SW-Distributionsseite nicht mehr den LD_LIBRARY_PATH zu benutzen. Dieser sollte nur noch dem Benutzer vorbehalten sein um seine speziellen Wünsche abzudecken.

Dieses Verhalten, sowie eine genauere Beschreibung des Suchmechanismus unter Mac OS X, ist in der Präsentation über Portablen Code aktualisiert.