Im vorherigen Teil ging es darum, wie man unter Linux Extended Attributes auf der Kommandozeile bearbeitet. Das Thema diesmal ist, mit welchen Syscalls man dies in C erledigen kann.
Für die 4 verschiedenen Operationen die man benötigt, nämlich listxattr, getxattr, setxattr und removexattr, gibt es jeweils 3 Syscalls.
#include <sys/types.h>
#include <sys/xattr.h>
ssize_t listxattr(const char *path, char *list, size_t size);
ssize_t llistxattr(const char *path, char *list, size_t size);
ssize_t flistxattr(int fd, char *list, size_t size);
ssize_t getxattr(const char *path, const char *name,
void *value, size_t size);
ssize_t lgetxattr(const char *path, const char *name,
void *value, size_t size);
ssize_t fgetxattr(int fd, const char *name,
void *value, size_t size);
int setxattr(const char *path, const char *name,
const void *value, size_t size, int flags);
int lsetxattr(const char *path, const char *name,
const void *value, size_t size, int flags);
int fsetxattr(int fd, const char *name,
const void *value, size_t size, int flags);
int removexattr(const char *path, const char *name);
int lremovexattr(const char *path, const char *name);
int fremovexattr(int fd, const char *name);
Die Syscalls mit dem l-Prefix liefern für den Fall dass path ein Symlink ist die Attribute des Symlinks selber, und nicht von der Datei, auf die der Symlink zeigt.
Bei den Syscalls mit dem f-Prefix übergibt man statt des Pfades einen Filedescriptor, den man mit open erhält.
Mit listxattr erhält man eine komplette Liste aller Extended Attributes für die Datei. Man muss einen vorher allozierten Buffer und seine Größe übergeben. Die Namen der Extended Attributes werden dann in diesen Buffer geschrieben, getrennt immer durch ein 0-Byte. Falls der Buffer zu klein ist, liefert die Funktion -1 zurück und setzt errno auf ERANGE. Man kann auch abfragen, wie groß der Buffer sein müsste, in dem man als size 0 übergibt. Der Rückgabewert ist dann die benötigte Größe des Buffers.
Hier ist ein Beispielprogramm, dass alle Extended Attributes einer Datei auflistet. Der Code um die Liste der Namen zu erhalten ist:
char *list = malloc(BUF_LEN);
ssize_t len = listxattr(path, list, BUF_LEN);
Wenn wir die Namen der Attribute haben, können wir den Wert mit getxattr erhalten. Diese Funktion erwartet ebenfalls einen Buffer, in den der Wert dann geschrieben wird. Auch hier kann man für size 0 angeben, um die Länge des Attributwerts zu erhalten.
Um das Beispielprogramm zu erweitern, dass es auch die Werte der Attribute ausgibt, könnte man die for-Schleife am Ende durch diesen Code ersetzen:
// print attributes
int begin = 0;
for(int i=0;i<len;i++) {
if(list[i] == '\0') {
char *xattr_name = list + begin;
char value[0x10000];
ssize_t vallen = getxattr(path, xattr_name, value, 0x10000);
printf("%s: %.*s\n", xattr_name, (int)vallen, value);
begin = i + 1;
}
}
Es fehlt zwar die Fehlerbehandlung, es sollte jedoch immer funktionieren. Die Größe ist eh auf 64kb beschränkt, bei vielen Dateisystemen sogar noch weniger.
Kommen wir zu setxattr, mit dem man ein Extended Attribute setzt. Die Funktion erwartet als letzten Parameter ein flag. Ist dies 0, wird der Wert gesetzt, egal ob er schon existiert oder nicht. Bei XATTR_CREATE liefert die Funktion einen Fehler, wenn das Attribut schon existiert und bei XATTR_REPLACE gibt es einen Fehler, wenn der Wert nicht existiert.
xsetattr(path, "user.myattrname", value, valuelen, 0);
Bleibt zuletzt noch removexattr, dem man einfach nur den Dateipfad und den Attribut-Namen gibt, und der wird dann entfernt.
Normale Attribute einer Datei sind Dinge wie der Besitzer und einfache Unix-Zugriffsrechte. Es gibt daneben aber noch erweiterte Dateisystemattribute. Das sind beliebige name/value-Paare, die man für Dateien setzen kann.
Linux unterstützt Extended Attributes in der Regel. Der Kernel muss das Feature aktiviert haben, was per Default der Fall ist, und das Dateisystem muss es ebenfalls unterstützen und gegebenenfalls mit einer bestimmten Option gemountet sein. Dies ist in gängigen Distributionen alles der Fall. Ich hab es unter CentOS, Debian, Ubuntu und openSUSE getestet und es ging alles. Die üblichen Dateisysteme (ext*, xfs, jfs, btrfs, f2fs) unterstützen Extended Attributes. Mit ZFS on Linux geht es auch. Allerdings unterstützt NFS unter Linux keine Extended Attributes.
Wie schon erwähnt hat jedes Extended Attribute einen Namen und einen Wert. Der Name besteht aus einem Namespace gefolgt von einem Punkt und dem eigentlichen Namen. Es gibt 4 Namespaces: user, trusted, security und system. Der user Namespace ist frei für alles benutzbar. Die anderen Namespaces werden unter anderem für SELinux (security) oder für Posix-ACLs (system) genutzt.
Um Extended Attributes zu modifizieren oder anzuschauen gibt es die beiden Commandline-Tools getfattr und setfattr. Unter Debian und Ubuntu müssen diese erst mit dem Paket attr nachinstalliert werden. CentOS und openSUSE haben die Tools out of the box dabei. Die Benutzung ist recht einfach.
$ echo "hello" > test.txt
$ setfattr -n user.test -v "xattr test string" test.txt
$ setfattr -n user.mime_type -v "text/plain" test.txt
$ getfattr test.txt
# file: test.txt
user.mime_type
user.test
$ getfattr -n user.test test.txt
# file: test.txt
user.test="xattr test string"
Auch einige andere Tools unterstützen Extended Attributes, leider jedoch nicht alle, oder sie können es, aber machen einen das Leben etwas schwerer. Verschiebt man eine Datei mit mv bleiben die Extended Attributes erhalten, falls das Zieldateisystem diese unterstützt. Wenn nicht werden diese heimlich ohne Warnung entsorgt. GNU cp kopiert sie standardmäßig nicht mit, allerdings mit der Option --preserve=xattr werden sie mitkopiert. Mit GNU tar muss man sowohl beim Packen als auch Entpacken die Option --xattrs angeben. Und wenn man mit Gnome über die GUI ein Archiv erstellt, werden keine Extended Attributes gespeichert. Nautilus hingegen kopiert sie brav mit.
Ich finde es ist eigentlich ein interessantes Feature, was erstaunlich wenig von Anwendungen genutzt wird. Eins der wenigen Beispiele wo Extended Attributes eingesetzt werden ist bei Apache, wo damit Mime-Types oder Charsets für Dateien festgelegt werden können.
Beim Zugriff über ssh auf ein etwas älteres Unix wie z.B. Solaris 10 erhält man in vi oder manchen anderen Terminal-Anwendungen eine Fehlermeldung wie
xterm-256color: Unknown terminal type
Die Anwendung ist dann meistens nicht oder nur eingeschränkt benutzbar.
Die triviale Lösung ist einfach die TERM-Umgebungsvariable auf xterm zu setzen. Wenn man das nicht immer manuell machen will, kann man das einfach in der .profile Datei (oder .bash_profile, wenn die Login-Shell die bash ist) folgendes hinzufügen:
if [ $TERM = "xterm-256color" ]; then
TERM=xterm
export TERM
fi
Wenn man root-Rechte auf dem Server hat, gibt es auch noch eine andere Lösung. Es gibt eine Terminfo-Datenbank, die für die verschiedenen Terminal-Typen die Fähigkeiten enthält. Den fehlenden Eintrag für das xterm-256color Terminal kann man einfach hinzufügen.
Unter Solaris 10 finden sich die Terminfo-Dateien unter /usr/share/lib/terminfo. Dort gibt es für jeden möglichen Anfangsbuchstaben ein Verzeichnis, die xterm Einträge sind daher unter /usr/share/lib/terminfo/x. Dort muss eine Datei xterm-256color rein. Die ganz einfache Lösung wäre einfach die xterm-Datei zu kopieren. Ich hab hingegen die xterm-256color-Datei von einem Solaris 11 dort eingefügt. Beides funktioniert und sobald diese Datei da ist, erkennen Anwendungen auch das xterm-256color-Terminal.
Hardware-RAID hat gegenüber ZFS so einige Nachteile. Keine Checksums, resilvern dauert lange, Inkompatiblitäten zu anderen RAID-Controllern, da ist man echt froh, wenn man das nicht hat. Ein Argument gegen ZFS ist allerdings der Ressourcen-Verbrauch, denn statt Hardware-RAID-Controllern muss jetzt Software den selben Job und noch mehr erledigen. Spüren tut man das allerdings nicht, denn die CPUs sind heutzutage so schnell, dass die das locker nebenbei erledigen.
Dieses prähistorische Dinosaurier-RAID ist vielleicht nicht so toll, doch wenn man nur die passenden Dinosaurier-CPUs dazu hat, dann hat das ganze doch ein paar Vorteile. Ich habe kürzlich auf einer Sun Ultra 25 Workstation ein raidz1 mit 3 Platten gebildet. Die Workstation stammt aus dem Jahr 2006, die darin verbaute UltraSPARC IIIi CPU gibt es allerdings seit 2003. Und damit merkt man leider schon, was ZFS so an Rechenleistung verbrennt.
Ein Ausschnitt der Ausgabe von prstat wärend mit dd auf den raidz1 pool geschrieben wurde:
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
107 root 0K 0K run 0 -20 0:00:25 58% zpool-storage/136
967 root 4624K 2152K run 53 0 0:00:08 12% dd/1
Und wenn parallel dazu noch auf den rpool, der nur aus einer Festplatte besteht, geschrieben wurde:
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
107 root 0K 0K sleep 99 -20 0:01:55 41% zpool-storage/136
980 root 4624K 2216K sleep 53 0 0:00:04 11% dd/1
5 root 0K 0K run 0 -20 0:00:23 6,1% zpool-rpool/136
981 olaf 4624K 2320K run 39 0 0:00:01 4,1% dd/1
Es ist also doch kein Mythos, dass ZFS ein paar Ressourcen braucht. Und ein zpool scrub verursacht sogar über 90% CPU-Auslastung.
Ich finde den Fall einfach zu erbärmlich um ihn nicht zu erwähnen.
User creation dialog design and usability
Linux-Desktops wird oft nachgesagt, dass sie inkonsistente Userinterfaces haben, jede Anwendung nutzt ein anderes Toolkit mit anderem Look and Feel. Das Design stammt oft von irgendwelchen C-Hackern, die keine Ahnung von GUI-Gestaltung haben. Aber alle diese Probleme hat man mitlerweile auch bei Windows. Jede Microsoftanwendung hat ein anderes Look and Feel. Und solche lächerlichen Fehler wie uneinheitliche Positionen für Buttons darf es bei einem so großen Unternehmen nicht geben.
Kommentare
dev | Artikel: Datei ver- und entschlüsseln mit openssl - kompatibel mit dav
Andreas | Artikel: Datenanalyse in der Shell Teil 1: Basis-Tools
Einfach und cool!
Danke Andreas
Rudi | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Peter | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Damit wird Nedit durch XNedit ersetzt.
Danke!
Olaf | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Anti-Aliasing hängt von der Schriftart ab. Mit einem bitmap font sollte die Schrift klassisch wie in nedit aussehen.
Einfach unter Preferences -> Default Settings -> Text Fonts nach einer passenden Schriftart suchen.
Peter | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Mettigel | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Ich hatte gedacht, dass der GX-415 im s920 deutlich mehr Dampf hat als der Raspi4.
Mein Thinclient verbraucht mit 16 GB RAM ~11 W idle, das ist das Dreifache vom RP4. Das muss man dem kleinen echt lassen... Sparsam ist er.
Olaf | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Ergebnisse von der Ultra 80 wären natürlich interessant, insbesondere im Vergleich mit dem rpi1.