Archiv der Kategorie: Software

Alles was mit Software zu tun hat

CUPS/foomatic/gutenprint: „Unable to get list of printer drivers: Success“

Eigenlich bin ich ja Verfechter papierloser Abläufe, leider sind viele Behörden damit nicht einverstanden oder schreiben sinnloserweise selbstgestrickte Vorgaben statt offener Standards vor. Zum Glück stehen hier noch ein paar Drucker aus den 80ern und 90ern rum, die nicht nach 10 Seiten das Zeitliche segnen. Also: Drucker raus, Papier rein. Error. Bei der Installation des Druckers auf meinen PCs – genauer der Suche nach möglichen Treibern – meldete CUPS teilweise folgende, sehr aussagekräftige, Fehlermeldung:

Unable to get list of printer drivers: Success

Auffällig dabei: Ein Perl-Script bezüglich Foomatic belagert zuvor einen CPU-Kern. Auch konnte ich bei einem System beobachten, dass der Fehler erst nach Installation zusätzlicher Treiber (foomatic-db & Co) auftrat, mit „leerer“ Treiber-Liste jedoch nicht. Der Fehler ist konstant, also sowohl in der Desktop-GUI als auch im CUPS-Webinterface reproduzierbar.

tl;dr: Don’t do gutenprint…

Schauen wir mal genauer auf den 100%-Prozess: Dieser wird vom Nutzer „daemon“ gestartet und hat kein nice-Level. Der genaue Aufruf lautet

/usr/bin/perl /usr/lib/cups/driver/foomatic list

Das Script selbst lässt sich auch auf der Konsole manuell starten. „list“ gibt hierbei nicht wirklich etwas – auch nach mehreren Minuten keine Ausgabe. „help“ am Ende zeigt die möglichen Optionen:

foomatic -A
foomatic -P
foomatic -p [-d ] [-w]
foomatic list
foomatic cat [-w]
foomatic -h

-A : show all Printer ID’s and compatible drivers
-P : show all Printer ID’s whose names and model
matched by the RE. For example:
-P HP will match all names with HP in them
-p : Printer ID
-d : Driver name
If the driver is not specified then the default driver
for the is used.
list : List all possible PPDs in the format needed by the
cups-driverd
cat : Generate PPD file appropriate to the .
Available CUPS PPD URIs are listed by
„foomatic list“.
-w : Generate PPD which is compatible with the CUPS PostScript
driver for Windows (GUI strings are limited to 39
characters).
-h : show help information

Leider scheint es – jedenfalls laut Hilfe – keinen verbose- oder debug-Modus zu geben. Strace to the rescue. Zu sehen nicht viel – die Treiber-Dateien werden nacheinander geladen, die letzten Zeilen lauten:

stat(„/usr/share/foomatic/db/source/driver/xes.xml“, {st_mode=S_IFREG|0644, st_size=522, …}) = 0
stat(„/usr/share/foomatic/db/source/driver/xes.xml“, {st_mode=S_IFREG|0644, st_size=522, …}) = 0
stat(„/usr/share/foomatic/db/source/driver/xes.xml“, {st_mode=S_IFREG|0644, st_size=522, …}) = 0
open(„/usr/share/foomatic/db/source/driver/xes.xml“, O_RDONLY) = 3
lseek(3, 0, SEEK_CUR) = 0
read(3, „\n

Dummerweise ist „xes.xml“ auch die alphabetisch letzte Datei, also eher kein Fehler darin zu vermuten. Narf. Nunja – räumen wir mal auf. Unter /usr/share/foomatic/db/source müssen die Dateien unter PPD, driver, opt und printer weichen. Success. Kind of. Der Foomatic-Prozess endet ohne Fehler, also muss einer der Treiber der Übeltäter sein. Als erstes wandert opt wieder zurück, hier ist nicht viel drin. Noch alles OK. Auch das zurückkopieren von PPD zeigt keine Änderung. Printer klingt interessanter, daher spiele ich hier jede Datei einzel zurück:

for i in * ;do mv $i ../printer && echo $i && (/usr/bin/perl /usr/lib/cups/driver/foomatic list || exit) ; done

Dauert zu lange – ich entscheide mich nur die XML-Dateien der für mich interessanten Hersteller zu nutzen. Läuft noch. Es folgt Drivers. Weniger dateien, trotzdem manuell. Erster Kandidat: necp6 – ein Treiber für meinen Nadeldrucker. Passt – foomatic list liefert nun eine Liste aller NEC-Nadeldrucker. Fehlt noch mein Laser. Da Gutenprint schnell sein soll kopiere ich deren XMLs – nichts geht mehr. Hört sich nach Verursacher an – kopieren wir alles außer Gutenprint: Passt. Auch in CUPS lässt sich nun der Drucker anlegen. Fehler Gefunden würde ich sagen…

Backup Exec: Speicherplatzbedarf bändigen

Symantec Backup Exec kennt seine Backups – leider für einige Fälle zu gut. Standardmäßig wird für jede Sicherung eine Liste der gesicherten Daten, also z.B. die Liste aller Dateien, im Katalog auf der Festplatte des Backupservers abgelegt. Wird das Zielmedium später überschrieben werden auch die Daten gelöscht – wer jedoch Langzeitsicherungen erstellt oder Sicherungsdatenträger aussortiert wird auf Dauer mit einem nicht unerheblichen Platzverbrauch konfrontiert. Mehrere hundert Gigabyte sind so schnell zusammen, welche üblicherweise unter %ProgramFiles%\Symantec\Backup Exec\Catalogs\*SERVERNAME* landen. Doch sind diese Daten wirklich noch notwendig? Ist es nicht auch akzeptabel bei Rücksicherungen, welche älter als einige Monate sind, einige Minuten länger zu warten und bei Bedarf den Katalog neu vom Zieldatenträger zu laden? Um hier Ordnung zu schaffen gibt es gleich drei Lösungen

1. Katalog verschieben

Wer noch an anderer Stelle genügend Platz hat und die Kataloge weiterhin im Direktzugriff haben möchte kann den Katalogordner an ein anderes Ziel verschieben. Die nötigen Infos sind unter TECH74582 zu finden – zwar für deutlich ältere Versionen, die Option sollte sich jedoch auch weiterhin in den Menüs verstecken.

2. Kataloglebensdauer einstellen

In den Optionen gibt es die Möglichkeit Dateilisten nach einer gewissen Zeitspanne zu verwerfen. Der zugehörige Artikel findet sich unter TECH7297 – die Option ist wie auch zuvor in den Menüs weiterhin zu finden. Leider greift die Option nur für neu angelegte Kataloge, ältere müssen ggf. manuell entfernt werden.

3. Manuelles löschen

Auch manuell lässt sich der Ordner aufräumen. Hierzu müssen erst alle Dienste des Backup Exec-Systems gestoppt werden. Im Anschluss löscht man alle *.fh und *.xml-Dateien im Katalogverzeichnis, welche älter als das gewünschte Datum sind. Andere Dateien sollen laut Symantec-Forum nicht gelöscht werden – zwar denke ich nicht, dass diese Aussage für Einträge mit gleichen UUIDs korrekt ist, da die übrigbleibenden Dateien jedoch nur wenige KB groß sind habe ich dies nicht weiter geprüft. Da nun Datenbank und Ordner inkonsistent sind ist ein Reinigungslauf notwendig, hierzu startet man im BE-Verzeichnis den Befehl „CatRebuildIndex.exe -r“ als Administrator. Dies kann einige Zeit in Anspruch nehmen.

Alles keine schönen Lösungen, aber irgendwann ist auch der größte Platz mal voll und Migrieren macht mit Windows keinen Spaß.

Gluon: Build vox x86-Images schlägt fehl

Seltsames Fehlerbild: Mit dem neuen Gluon-Release sind einige Hardwareplattformen hinzu gekommen, alle lassen sich Fehlerfrei bauen, nur die x86-basierten Images machen Probleme. Der Fehler ist im Debugmodus (make … V=s) schnell lokalisiert: Es wird versucht ein ext4-System zu konfigurieren, hierbei wird automatisch geprüft, ob das betroffene System irgendwo gemountet ist. In meinem Fall läuft der Build in einer chroot, da dort die mtab fehlt schlägt diese Prüfung und damit auch der Build fehl.

/home/openwrt/gluon-trunk/upstream/build/x86-generic/openwrt/staging_dir/host/bin/tune2fs  -O extents,uninit_bg,dir_index /home/openwrt/gluon-trunk/upstream/build/x86-generic/profiles/GENERIC/kernel/root.ext4
tune2fs 1.42.8 (20-Jun-2013)
ext2fs_check_if_mount: Can't check if filesystem is mounted due to missing mtab file while determining whether /home/openwrt/gluon-trunk/upstream/build/x86-generic/profiles/GENERIC/kernel/root.ext4 is mounted.
Makefile:269: recipe for target 'install' failed

Da in der chroot /proc verfügbar ist lässt sich das Problem mit einem einfachen Symlink lösen:

ln -sf /proc/mounts /etc/mtab

…und schon läuft der Build wie erwartet.

Fujitsu Scanner-Fehler mit Sane & aktuellen Kernel

Dokumentenscanner von Fujitsu sind schnell und teuer – es sei denn die Windows-Unterstützung fällt weg. Ältere Modelle wie der fi-4120 laufen nur bis Windows XP zuverlässig, mit Windows 7/8/10 schaut man in die Röhre, vor allem wenn 64 Bit im Spiel sind. Kein Wunder, dass die ehemals fast 700€ teuren Geräte jetzt für gebraucht für wenig Geld zu finden sind. Unter Linux ist das ganze eigentlich recht entspannt: Die Geräte werden durch Sane unterstützt und sind entsprechend problemlos nutzbar. Ich selbst habe einen solchen schon länger an einem Raspi im Betrieb um Briefe & Co. zu digitalisieren.

Leider scheint das „Problemlos“ momentan eine Auszeit zu nehmen: Bei anderen Anwendern aus der hiesigen Linux User Group macht der Scanner in letzter Zeit Probleme: Nach dem Einschalten sieht alles OK aus, versucht man jedoch zu scannen erhält man einen „Error during device I/O“. Am OS sollte es nicht hängen – sowohl mein Raspi als auch der betroffene Rechner laufen mit Arch. Auch die „üblichen“ Tipps, namentlich „keine USB-Hubs“, trafen nicht zu.

Also: Debuggen. Während bei meinem Netbook und dem Raspi keine Fehler auftreten kann ich ihn mit Laptop und einem PC nachvollziehen. Erstere arbeiten mit ARM bzw. einer 32 Bit CPU und unterstützen nur USB 2.0, letztere sind 64 Bit mit USB 3.0. Zur Übersichtlichkeit habe ich erst mal alle Treiber außer Fujitsu aus /etc/sane/dll.conf entfernt. Den Debug-Modus für Sane und den Treiber aktiviert man mit folgenden Zeilen:

export SANE_DEBUG_DLL=255
export SANE_DEBUG_FUJITSU=35

Nach dem Einschalten taucht der Scanner wie üblich in lsusb auf. Auch sane-find-scanner kann die USB-ID erkennen. scanimage -L zeigt dem Scanner im ersten Durchlauf ebenfalls, führt man den selben Befehl jedoch erneut aus tauchen USB-Fehler auf. IO-Error, Invalid Argument, etc. Ausgerüstet mit den passenden Logs findet sich in den Quellen des Sane-Projektes ein passender Commit vom 16.12.2014, welcher einen Workarround für aktuelle Kernel-Images bereitstellt. Hier ist offenbar eine Regression, welche die Ansteuerung der Fujitsu-Scanner betrifft. Worth a try, also schnell mal das ältere sane-Paket deinstalliert und stattdessen sane-git aus AUR installiert. Siehe da: Läuft. Soweit ich erkenne betrifft der Fehler nur einige USB-Controller, was ggf. erklärt warum ich auf meinem Raspi keine Fehler finden konnte.

tl;dr: GIT ist manchmal doch funktionsfähiger als stable

[Javascript] Input-Felder klonen ohne JQuery

Für eine Parametererfassung benötige ich ggf. mehrere Felder für einen Wert. Generell kann man natürlich genügend Felder vorab erstellen, jedoch ist in meinem Fall nicht klar wie viele benötigt werden. Die Idee: Es ist nur ein Feld verfügbar, wird dies jedoch genutzt erstellt sich automatisch ein Weiteres hinter dem ersten Feld. Die meisten Beispiele nutzen JQuery, da meine Lust Externes einzupflegen nicht grade überwältigend groß ist musste VanillaJS herhalten.

<input type="text" name="Element1[]" onClick="clone.call(this)">

function clone() {
    var newNode = document.createElement(this.tagName);
    switch(this.tagName) {
         case "INPUT":
               newNode.type = this.type;
               newNode.name = this.name;
               newNode.value = "";
               newNode.onclick = function() { clone.call(this) };
               break;
                             
    }
    this.onclick = undefined;
    this.parentNode.insertBefore(newNode, this.nextSibling);
}

Sinnvoller als onclick wäre natürlich onchange, aber hey, Konzept funktioniert…

Monitorprofile mit xrandr-mgr

Mehrere Monitore machen Spaß. An meinem Hauptplatz werkeln 4 TFTs an einem Rechner – Mail, Code, Testausgaben, Medien – alles ist irgendwo dauerhaft sichtbar. Was etwas nervig ist sind jedoch Spiele: Diese landen unabhängig von der Primärmonitordefinition immer auf dem linken Monitor. Bisher habe ich hier manuell mit xrandr nachgeholfen und vor Start des Spiels meinen Desktop auf den TFT vor meiner Nase beschränkt. Leider hat xrandr keine undo-Button, das heißt nach dem Spielen musste ich immer wieder per Hand nachhelfen.

Heute ich mir das Tool xrandr-mgr begegnet, welches das anlegen von benannten Profilen erlaubt. Für mich nicht direkt nutzbar, da sich meine Konfiguration häufig ändert, aber für ein temporäres Merken des vorherigen Konfiguration trotzdem Ideal.

YouTube Watch Later als M3U-Playlist exportieren

Ein großer Teil meines Medienkonsums läuft über YouTube. Bastler, Podcasts, Vorträge – nahezu alles ist hier vorhanden und hat den Fernseher nahezu vollständig abgelöst. Eine der aufwändigsten Arbeiten für mich ist es meine „Wunschliste“ an Videos zu verwalten. Welche Videos möchte ich mir noch ansehen. Hierzu nutze ich bereits seit längerem einige Scripte um Posts diverser Channels zu sortieren und Interessantes in die „Watch Later“-Liste, also „Später ansehen“, zu verschieben. Diese kann ich dann einfach auf dem Tablet laufen lassen und so die Videos nach und nach ansehen.

Anders sieht es aus wenn ich am PC arbeite. Zwar kann man auch hier die Liste über die Webseite nutzen, jedoch ist hier ohne Klimmzübe kein Overlay („Immer im Vordergrund“) möglich. Als Abhilfe nutze ich hier üblicherweise VLC – dort kann man eine YouTube-URL eingeben und direkt abspielen. Leider gibt es keine direkte Unterstützung für Playlisten und die verfügbaren Plugins lassen nur öffentliche Listen abrufen.

Bild:

Natürlich könnte ich jetzt meine Scripte umschreiben und öffentliche (bzw. „Nicht gelistete“) Listen nutzen, jedoch ist das manuelle Hinzufügen zur Watch-Later-List dank des überall verfügbaren Buttons wesentlich einfacher als das Hinzufügen zu selbst angelegten Listen.

Bild: https://adlerweb.info/blog/wp-content/uploads/2015/04/wll.png

Da ich von LUA, welches in VLC zum Einsatz kommt, keine Ahnung habe und durch meine sonstigen YT-Automationen tonnenweise fertigen PHP-Code zur Verfügung habe ist entsprechend eine Webanwendung daraus geworden. Benötigt wird ein API-Key, welcher in der Dev-Console beantragt werden kann sowie die Installation des Google API PHP-Client. Auch sollte der Webserver die Berechtigung haben key.php im selben Verzeichnis zu beschreiben – dies kann z.B. über „touch key.php ; chmod ugo+w key.php“ erfolgen. Der erste Aufruf sollte über den Browser erfolgen, hierbei wird man aufgefordert das Script mit YouTube zu Paaren. Die so abgerufenen Schlüssel werden in den angesprochenen key.php gespeichert, sodass folgende Zugriffe ohne weitere Abfragen erfolgen. Die URL kann nun in VLC eingefügt werden – dieser sollte die so bereitgestellte Playlist laden und die Videos nacheinander abspielen – mit allen Features des VLC wie z.B. Always-on-Top, Abspielgeschwindigkeit, Videoeffekte, etc.

Bild: https://adlerweb.info/blog/wp-content/uploads/2015/04/playlist-300×266.png

Den Code zum selbst testen gibts anbei oder – ohne WordPress-Korrekturversuche – im Gist. Eventuell ließ sich das Ganze auch noch mit youtube-dl kombinieren um einen Podcast-kompatiblen Feed zu erstellen.

< ?php

/**
 * Youtube Watch Later List To Playlist Script
 * 
 * This script fetches your watch later list and outputs it as an M3U playlist
 *
 * Requirements:
 *   PHP enabled webserver
 *   Google PHP API (https://github.com/google/google-api-php-client)
 *   A YouTube API key (Oauth2, can be registered at https://console.developers.google.com/)
 *   Some kittens to sacrifice
 *
 * Initialization
 *   First ensure your webserver can write a file called "key.php" to the directory
 *   you put this file in. E.g. "touch key.php ; chmod ugo+w key.php"
 *   Next open the appropriate URL in your browser. You will be asked to pair
 *   this script with your YouTube-Account. If you configured everything correctly
 *   it will output the playlist and save your access codes in the key.php mentioned
 *   above. Successive requests do not require additional authentication. You may now
 *   put the URL in your YT-enabled media player like VLC.
 *
 * Based on examples by DomSammut (https://www.domsammut.com/code/php-server-side-youtube-v3-oauth-api-video-upload-guide)
 * 2015 Florian Knodt 
 */ 

// Set this to the directory of google api php client
set_include_path('./google-api-php-client/src/');

$OAUTH2_CLIENT_ID = 'YOURID.apps.googleusercontent.com';
$OAUTH2_CLIENT_SECRET = 'YOURSECRET';
$REDIRECT = 'http://localhost/yt/ytwll2m3u.php';
$APPNAME = 'YouTube WLL Import Test';

require_once 'Google/autoload.php';
session_start();

$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setApplicationName($APPNAME);
$client->setAccessType('offline');

if(file_exists('key.php')) {
    require_once 'key.php';
}

if(isset($key)) {
    $client->setAccessToken($key);
    $_SESSION['token'] = $key;
}else{
    $client->setScopes('https://www.googleapis.com/auth/youtube');
    $client->setRedirectUri($REDIRECT);
}

// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);

if (isset($_GET['code'])) {
    if (strval($_SESSION['state']) !== strval($_GET['state'])) {
        die('The session state did not match.');
    }
 
    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();
 
}
 
if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
    $keydata = '< ?php $key=\''.$_SESSION['token'].'\'; ?>';
    //echo '' . $_SESSION['token'] . '';
   
    if(!is_writable('key.php')) {
        die('key.php can not be written - please put this code into key.php: '.$keydata);
    }
    file_put_contents('key.php', $keydata);
}

// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
    try {
        // Call the channels.list method to retrieve information about the
        // currently authenticated user's channel.
        $channelsResponse = $youtube->channels->listChannels('contentDetails', array(
            'mine' => 'true',
        ));
 
        $playlist = '#EXTM3U'."\n";
        foreach ($channelsResponse['items'] as $channel) {
            // Extract the unique playlist ID that identifies the list of videos
            // uploaded to the channel, and then call the playlistItems.list method
            // to retrieve that list.
            $uploadsListId = $channel['contentDetails']['relatedPlaylists']['watchLater'];
 
            $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                'playlistId' => $uploadsListId,
                'maxResults' => 50
            ));
 
            foreach ($playlistItemsResponse['items'] as $playlistItem) {
                $playlist .= '#EXTINF:-1,'.$playlistItem['snippet']['title']."\n".'https://www.youtube.com/watch?v='.$playlistItem['snippet']['resourceId']['videoId']."\n";
            }
            
            while(isset($playlistItemsResponse['nextPageToken'])) {
                $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                    'playlistId' => $uploadsListId,
                    'maxResults' => 50,
                    'nextPageToken' => $playlistItemsResponse['nextPageToken'],
                ));
                foreach ($playlistItemsResponse['items'] as $playlistItem) {
                    //$htmlBody .= sprintf('
  • %s (%s)
  • ', $playlistItem['snippet']['title'], //$playlistItem['snippet']['resourceId']['videoId']); $playlist .= '#EXTINF:-1,'.$playlistItem['snippet']['title']."\n".'https://www.youtube.com/watch?v='.$playlistItem['snippet']['resourceId']['videoId']."\n"; } } } } catch (Google_ServiceException $e) { echo sprintf('

    A service error occurred: %s

    ', htmlspecialchars($e->getMessage())); } catch (Google_Exception $e) { echo sprintf('

    An client error occurred: %s

    ', htmlspecialchars($e->getMessage())); } $_SESSION['token'] = $client->getAccessToken(); } else { $state = mt_rand(); $client->setState($state); $_SESSION['state'] = $state; $authUrl = $client->createAuthUrl(); $htmlBody = < <Authorization Required

    You need to authorise access before proceeding.

    END; } if(isset($playlist)) die($playlist); ?> < !doctype html> My Uploads < ?php echo $htmlBody?>

    Logrotate für Windows-Webserver IIS

    Seriously, Microsoft? Der in Windows integrierte Webserver IIS kann problemlos vernünftige Log-Dateien erzeugen und besitzt auch eine Funktion diese bei Erreichen einer Zeitspanne oder eines Größenlimits zu schließen und eine neue beginnen. Was leider fehlt: Alte Dateien löschen. Es kommt was kommen musste: Auf einem Produktivserver durfte ich mehr als 100GB an logtechischen Textkauderwelsch finden. Platte voll.

    Zwar kann man hier mit der in NTFS verfügbaren Ordnerkompression gegensteuern, eine Dauerlösung ist das aber sicher nicht. Am Ende habe ich auf Basis eines Powershell-Scriptes von Daniel Schroeder aka deadlydog etwas passendes gebastelt um hier Abhilfe zu schaffen. Regelmäßig über die Aufgabenplanung aufgerufen bleibt so der Ordner auf einem erträglichen Maß.

    $limit = 15 #Delete Logs after 15 Days
    $path = "C:\inetpub\logs\LogFiles\W3SVC1"
    
    # Function to remove all files in the given Path that have not been modified after the given date.
    # original written by deadlydog / Daniel Schroeder, http://blog.danskingdom.com/powershell-functions-to-delete-old-files-and-empty-directories/
    # Requires Powershell >=2.0
    function Remove-FilesNotModifiedAfterDate([parameter(Mandatory)][ValidateScript({Test-Path $_})][string] $Path, [parameter(Mandatory)][DateTime] $DateTime)
    {
        Get-ChildItem -Path $Path -Recurse -Force -File | Where-Object { $_.LastWriteTime -lt $DateTime } | Remove-Item
        #Get-ChildItem -Path $Path -Recurse -Force -File | Where-Object { $_.LastWriteTime -lt $DateTime } | Format-List BaseName,LastWriteTime
    }
    
    Remove-FilesNotModifiedAfterDate -Path "$path" -DateTime ((Get-Date).AddDays(1-$limit))

    Zum Ausführen wird mindestens PowerShell 2.0 benötigt. Ältere Betriebssysteme wie z.B. 2008R2 bringen nur PowerShell 1 mit, hier muss manuell über das Windows Management Framework aktualisiert werden.

    SSH: Fingerprint-Algorithmus ändern

    Bild: https://adlerweb.info/blog/wp-content/uploads/2015/04/sshmd5-300×45.pngMit einem der letzten Updates scheint OpenSSH einen Schritt in Richtung Gegenwart getätigt zu haben. Nun werden Fingerprints nicht mehr als MD5 sondern mit SHA256 präsentiert. Was auf der einen Seite eine tolle Sache ist kann aber auch zum Problem werden: Eine hiesige Debian-Kiste kann mit dem dort als stable deklarierten OpenSSH 7.0 auch optional keinen SHA256-Hash herausrücken. Manueller Abgeleich mit dem neueren Client des ArchLinux-Systems unmöglich. Um hier wieder auf einen gemeinsamen Nenner zu kommen bleibt nur den neuen Client auf den älteren Hash-Algorithmus zurückzutrimmen. Das funktioniert über die SSH-Config (/etc/ssh/ssh_config or ~/.ssh/config) mit folgenden Zeilen – zum Glück auch für einzelne Hosts:

    Host oldserver.org
    FingerprintHash md5

    Schon erhält man beim Verbinden wieder den gewohnten MD5-Hash und kann sich – bis auch andere Distros sha256 herausrücken – behelfen.

    Internet Explorer und die Kompatibilitätsmodi

    Auch wenn Microsoft ihn quasi schon beerdigt hat: Immer wieder stößt man noch auf den Internet Explorer. Gerade in Firmen ist er kaum wegzudenken, denn viele Produkte der Industrie haben es auch 2015 noch nicht geschafft auf ActiveX zu verzichten bzw. halbwegs standardisierte Formate zu verwenden. Besonders tückisch hierbei: Während die neueren Versionen des Internet Explorer immerhin halbwegs mit den aktuellen Webstandards klar kommen sind viele Webanwendungen noch auf ältere Inkarnationen zugeschnitten. Um hier den Nutzern keine Angst vor einer Aktualisierung zu bescheren schaltet der Internet Explorer beim kleinsten Anzeichen für Probleme in einen Kompatibilitätsmodus und behandelt die Inhalte wie frühere Versionen. Auch ist es nicht unüblich, dass alle internen Adressen automatisch immer mit den damaligen Vorgaben behandelt werden.

    Wer als Webentwickler für Firmen unterwegs ist sollte hier gegensteuern. Natürlich ist es einfach den jeweiligen Administratoren eine Änderung der Einstellungen oder gar einen anderen Browser zu empfehlen, jedoch ist dies häufig nicht mit Policies vereinbar oder aber wird als Ausnahme gehandhabt. Letztere werden gerne auf Grund der Seltenheit nur schlecht gewartet oder gehen mit der Zeit in den Tiefen des Systemmanagements verloren und sogen dann für aufwändige Fehlersuchspiele.

    Wer sich sicher ist, dass seine Seite mit aktuellen IE-Versionen läuft kann jedoch auch ganz ohne Firmenadministrator die meisten Probleme vermeiden. Über einen propritären Meta-Tag lässt sich der IE anweisen eine bestimmte Rendering-Art zu verwenden – unabhängig von der globalen Vorlage.

    Um beispielsweise explizit als IE11 zu rendern kann folgender Eintrag im head der Seite ergänzt werden:

    Selbes geht natürlich auch für andere Versionen. Eine Sonderstellung bildet noch „edge“ – hiermit wird immer die neueste verfügbare Engine genutzt. Perfekt wenn mann möglichst viele aktuelle Funktionen verfügbar machen will. Identifiziert sich dennnoch ein älterer Browser kann man immernoch per Browserweiche o.Ä. einen abgespeckten Content servieren ohne befürchten zu müssen unbeabsichtigt auch neuere IE-Versionen einzuschränken.

    Mehr Infos gibt es in einem Technet-Artikel von Stephanus Schulte, welcher das Thema ausführlich erklärt. Wer sich lieber auf die Fakten beschränkt wird im MSDN fündig.