Some tutorials suggest to use the system properties “http.proxyUser” and “http.proxyPassword” to get proxy authentication, but that won’t work since – in contrast to “http.proxyHost” and “http.proxyPort” – these properties will not be processed by Java’s HttpURLConnection.

Other suggest to use a custom default Authenticator. But that’s dangerous because this would send your password to anybody who asks.

The following snippet contains some code that uses an Authenticator to process “http.proxyUser”, but ensures that these information will be sent to the host that is defined by “http.proxyHost”:

// Java ignores http.proxyUser. Here come's the workaround.
Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        if (getRequestorType() == RequestorType.PROXY) {
            String prot = getRequestingProtocol().toLowerCase();
            String host = System.getProperty(prot + ".proxyHost", "");
            String port = System.getProperty(prot + ".proxyPort", "");
            String user = System.getProperty(prot + ".proxyUser", "");
            String password = System.getProperty(prot + ".proxyPassword", "");

            if (getRequestingHost().toLowerCase().equals(host.toLowerCase())) {
                if (Integer.parseInt(port) == getRequestingPort()) {
                    // Seems to be OK.
                    return new PasswordAuthentication(user, password.toCharArray());
                }
            }
        }
        return null;
    }
});

Wichtiger Hinweis: Dieses “HowTo” ist in erster Linie als Erinnerung für mich selbst gedacht. Wenn ich jemand anderem damit ebenfalls helfen kann freue ich mich, aber aus zeitlichen Gründen kann ich im Moment nur sehr begrenzt Support geben.

Ich betreibe den yaVDR als Client/Server-Anwendung. Im Server befinden sich zwei DVB-S(2)-Karten, der Client im Wohnzimmer ist über das LAN angebunden.

Der Frontend des Client ist der ganz normale vdr-sxfe (libxineoutput), bei Bedarf kann XBMC über das Menü oder eine Taste gestartet werden. De Server selbst wird als Client nur selten benutzt, und wenn, dann meistens für Videos oder Aufnahmen. Aus diesem Grund kommt dort der XBMC mit PVR-Addon als Frontend zum Einsatz.

Damit der auf dem Server laufende VDR keine DVB-S-Karte für sich selbst belegt, schaltet das VDR-Plugin suspendoutput nach einer kurzen Wartezeit den VDR (als Client) ab:

$ grep suspendoutput /etc/vdr/setup.conf
suspendoutput.MainMenu = 1
suspendoutput.ShowLogo = 0
suspendoutput.SuspendPaused = 0
suspendoutput.SuspendTimer = 600

Damit der Server den internen Client direkt nach dem Start beendet, hilft eine kleine Zeile in /etc/rc.local vor dem “exit 0″:

vdr-dbus-send /Remote remote.CallPlugin string:'suspendoutput'

Doch bei diesem Setup gibt es ein Problem, denn suspendoutput bewirkt, dass der automatische Shutdown (bzw. Standby) nach der “MinUserInactivity” des VDR bei Nichtverwendung ignoriert wird. Und selbst wenn dieser ausgelöst würde: Das laufende XBMC würde den Shutdown verhindern.

Gehen wir zuerst das einfachere Problem an. XBMC soll erst nach einem Tastendruck auf der Fernbedienung tatsächlich gestartet werden. Dies geht über das Templatesystem von yaVDR recht einfach:

$ cat > /etc/yavdr/templates_custom/etc/init/xbmc.conf/25_wait-for-remote << EOL
xset dpms force off
(irw | read -r) || true
xset dpms force on
EOL
$ process-template /etc/init/xbmc.conf 

Mit “xset” wird das Display ab- bzw. wieder eingeschaltet, und die Anweisung mit “irw | read -r” horcht auf die Fernbedienung und beendet sich nach der ersten Zeile (= dem ersten Tastendruck). Die Klammern und das “true” sind notwendig, damit ein Abbruch des “irw” durch ein “kill” nicht als Fehler interpretiert wird.

Dass der Shutdown überhaupt ausgelöst wird ist etwas schwieriger, wenn suspendoutput in Betrieb bleiben soll. Im Quelltext des Plugins gibt es sogar einen entsprechenden Codeschnipsel, der jedoch auskommentiert ist und so direkt erstmal nicht funktioniert.

Leider habe ich den Entwickler des Plugins per E-Mail nicht erreichen können, also habe ich mich selbst an die Arbeit gemacht und einen Patch geschrieben, der den Code aktiviert und einen entsprechenden Eintrag im Konfigurationsmenü ergänzt.

$ wget http://dau-sicher.de/stuff/vdr-plugin-suspendoutput-enable-shutdown.patch
$ apt-get source vdr-plugin-suspendoutput
$ cd vdr-plugin-suspendoutput-1.0.1
$ patch -p1 ../vdr-plugin-suspendoutput-enable-shutdown.patch
$ dpkg-buildpackage -rfakeroot -uc -b
$ sudo dpkg -i ../vdr-plugin-suspendoutput_1.0.1-28yavdr14~natty_amd64.deb

Nun kann in den Plugineinstellungen die Option “Shutdown after min user inactivity” aktiviert werden:

grep Shutdown /etc/vdr/setup.conf
suspendoutput.Shutdown = 1

Mit diesen Tricks sollte sich der Server nun nach der eingestellten Wartezeit in den Standby-Modus begeben und rechtzeitig zu einer Aufnahme wieder aufwachen, natürlich vorausgesetzt, dass gerade keine andere Aufnahme läuft.

Damit der Client den Server wieder aufweckt, modifiziert man am besten die Datei /etc/network/interfaces:

# The primary network interface
auto eth0
iface eth0 inet dhcp
    post-up /usr/sbin/etherwake AA:BB:CC:DD:EE:FF

AA:BB:CC:DD:EE:FF muss durch die MAC-Adresse (”Hardware address”) des Servers ersetzt werden, die man mit “ifconfig” ermitteln kann. Außerdem muss das Paket “etherwake” installiert sein. Andere Wake-On-Lan-Pakete sind natürlich auch geeignet, nur muss dann der Befehl hintre “post-up” entsprechend angepasst werden.

Ein kleines Problem gibt es immer noch: Nach einem Standby wird das Interface zwangsweise neu gestartet. Um das zu erzwingen hilft noch ein kleines Script:

$ cat > /etc/pm/sleep.d/40_etherwake << EOL
#!/bin/sh

case $1 in
     hibernate|suspend)
         #Befehl vor Wechsel in Suspend
         ;;
     thaw|resume)
         #Befehl nach aufwachen aus Suspend
         /etc/init.d/networking restart
         ;;
esac

Nun sollte der Client den Server beim Einschalten automatisch aufwecken.

Den Shutdown testen kann man übrigens am besten, in dem man eine “screen”-Session öffnet, den Shutdown-Befehl mit einer Verzögerung von 10 Sekunden auslöst, die Screen-Session mit STRG-A, STRG-D detached und sich auslogt:

$ sleep 10 &&  /usr/bin/vdr-dbus-send /Remote remote.HitKey string:'Power'; exit

Der Grund für diesen Umweg ist, dass der lifeguard in der Regel den Shutdown verhindert, solange noch ein Benutzer angemeldet ist.

Wenn ich mit ffmpeg Videos in das x264-Format (in einem mkv-Container) umkodieren will, stoße ich manchmal auf folgende Fehlermeldung:

Application provided invalid, non monotonically increasing dts to muxer in stream 1: 6010976 >= 6010976
av_interleaved_write_frame(): Invalid argument

Danach bricht ffmpeg ab. “dts” hat dabei übrigens nicht mit dem Tonformat “DTS” zu tun, dennoch liegt das Problem an der Tonspur, die offenbar nicht ganz standardkonform ist, auch wenn ein Videoplayer sie abspielen kann. Es gibt diverse Patches, die dieses Problem umgehen sollen, aber nach meiner Erfahrung funktionieren sich nicht in allen Fällen oder haben andere Nebenwirkungen (z.B. kurze Aussetzer).

Erfolgsversprechender ist es, Video- und Tonspur einzelnd zu kodieren (bzw. letztere entnehme ich meistens unverändert aus der Quelle) und diese danach zusammenzufügen. Theoretisch kann es dabei zwar zu Sync-Problemen kommen, aber wenn beides aus der gleichen Quelldatei stammt sollte es funktionieren.

Zuerst konvertiert man die Videospur:

$ ffmpeg -i quelle.vob \
# Verwende alle Kerne. Ggf. die Zahl der zu verwendenen CPU-Kerne angeben
    -threads 0 \
# Kein Audio und keine Untertitel (Subtitle)
    -an -sn \
# eigene Präferenzen für Videokodierung
    -vcodec libx264 -preset slow -tune film -level 41 -crf 23 \
Zieldatei im mkv-Format
    ziel-nosound.mkv

Anschließend fügt man die Tonspuren hinzu. In diesem Beispiel wollen wir die erste (englisch) und die dritte (deutsch) Tonspur aus der Quelle nehmen, wobei die deutsche jedoch vom Player standardmäßig ausgewählt werden soll:

$ mkvmerge \
# Ziel mit Tonspuren
    -o ziel.mkv \
# Optionaler Filmtitel
    --title "Titel des Films" \
# Nur Videospur (-A) aus temp. Ziel nehmen
    -A ziel-nosound.mkv \
# Keine Videospur (-D) und die Audiospuren 1 und 3 der Quelle...
    -D -a 1,3 \
# ...Sprachen und Standardspur in der Quelle...
    --language 1:eng --language 3:ger --default-track 3 \
# Video und Tonspur entstammen der selben Quelle, sonst file
    --append-mode track  \
    quelle.vob

Vorsicht, die Angabe der Sprache und der Standardspur bezieht sich auf die Nummer in der Quelldatei. Dementsprecend beziehen sich solche Parameter immer auf die nächste angegebene Quelldatei.

Danach sollte man die korrekte Zuordnung und die Synchronisierung der Tonspuren prüfen.

Andere Meinungen

25. Februar 2012

Ich bin ein bequemer Mensch. Wenn es ein Blog einmal in meine Bookmarks geschafft hat, dann bleibt es da sehr, sehr lange. Sogar scheinbar tote Blogs lösche ich nur selten, denn da erlebt man manchmal eine freudige Überraschung. Und auch wenn ich mit der Zeit feststellen sollte, dass der Autor in vielerlei Hinsicht anderer Meinung ist als ich selbst wird es von mir weiterhin fast täglich einmal besucht.

Ein solcher Kandidat in doppelter Hinsicht ist Don Alphonsos BlogBar, in der er heute einen wirklich wunderbaren Artikel über Fefes Blog bzw. genauer gesagt seine Kritiker veröffentlicht hat. Vielen Dank, Don, du sprichst mir aus der Seele!

JasperReports is a library which can be used to fill reports from Java applications or just create simple PDFs. It allows you to not only use static output strings but also Groovy expressions. Sadly, this is restricted to simple expressions that result in a value and don’t generate multiple class files at compile time.

For example, you could use the following expression to print different values depending if your document has more or less than 10 pages:

$V{PAGE_COUNT} < 10 ? "foo" : "bar"

But when you have to loop over values you’ll face a problem as you have no possibility to define own methods. Even the usage of closures (Groovy) or anonymous inner classes (Java) is prohibited as Jasper expects every expression to result in one single class file.

Of course you could extend the class path or use Scriptlets for this, but this requires you to ship the compiled class together with the report library.

Using the power of groovy there is a way to work around this: compile your expression at runtime! The following code will calculate the faculty of the number of pages:

new GroovyClassLoader().parseClass('''
    def static fac(x) {
        def res = 1;
        1.upto(x) {
            res *= it
        }
        return res
    }
''').fac($V{PAGE_COUNT})

The first line creates a new instance of the GroovyClassLoader, parses the code given in the following multiline string expression and executes the method “fac(x)” defined statically before.

To prove the power of this method the following code will embed a recursive listing of your home directory in your report:

new GroovyClassLoader().parseClass('''
    def static list(path, prefix) {
        String result = ""
        path.listFiles().each() {
            result += prefix + it.name + "\\n"
            result += list(it, prefix + "  ")
        }
        return result
    }
''').list(new File(System.getProperty("user.home")), "")

Remember that you have to double-escape backslashes as the first escape will be handles by the Jasper compiler.

Another possibility (and the reason why I researched at this topic) is that this method allows you to generate images at runtime and use the full power of the JFreeChart library used by Jasper itself.

JTextPane and his ancestors JEditorPane and JTextComponent won’t respect the color defined with setBackground(Color) since they display a “styled document” and expect the background color to be defined in the content. You’ll always see a white background.

To change the background color (without modifying the content) you have to define attributes for the document:

    JTextPane textPane = new JTextPane();
    textPane.setContentType("text/html"); // or any other styled content type
    textPane.setText("White text on a red background");

    textPane.setForeground(Color.white); // Works as expected
    textPane.setBackground(Color.red); // Obsolete, no affect

    // Define a default background color attribute
    Color backgroundColor = Color.red;
    SimpleAttributeSet background = new SimpleAttributeSet();
    StyleConstants.setBackground(background, backgroundColor);
    textPane.getStyledDocument().setParagraphAttributes(0,
            textPane.getDocument().getLength(), background, false);

    // And remove default (white) margin
    textPane.setBorder(BorderFactory.createEmptyBorder());

    // Alternative: Leave a 2px border but draw it in the same color
    textPane.setBorder(BorderFactory.createLineBorder(backgroundColor, 2));

Soeben habe ich die neuen 2TB-Festplatten in den Media-PC eingebaut und mich dazu entschieden, dieses mal dem neuen Linux-Dateisystem btrfs eine Chance zu geben. Im Gegensatz zum klassischen ext beherscht dieses nämlich von Haus aus RAID-Funktionalitäten (Level 0, 1 und 10) sowie Snapshots. Das RAID im Level 1 schützt vor physikalischen Fehlern, die Snapshots – sofern man sie regelmäßig anlegt – vor logischen, wie einem versehentlichen ‘rm -rf’.

Die Frage ist, wie stabil btrfs inzwischen geworden ist. Da es beinahe das Standardsystem unter Fedora 16 geworden wäre ist meine persönliche Einschätzung: Stabil genug für mich. Der Grund, warum FC16 doch noch ext4 verwendet, ist das fehlende bzw. nicht rechtzeitig fertig gewordene fsck. Mit den git-Quellen jedoch kein Problem, dort findet sich inzwischen ein ‘btrfsck’. Sowieso würde ich für den Einsatz einen aktuellen Kernel (3.x) und die aktuellen Tools aus dem Git-Repository verwenden, siehe https://btrfs.wiki.kernel.org/.

Zuerst müssen die Partitionen im RAID-1-Modus formatiert werden:

$ sudo mkfs.btrfs -L mediafiles -d raid1 -m raid1  /dev/sdd1 /dev/sde1

Im Gegensatz zu einem klassischen mkfs gibt man hier also zwei (bzw. mehr) Devices an. Mit den Parametern -d (–data) und -m (–metadata) wird der jeweilige Speichermodus festgelegt. Standardmäßig spiegelt btrfs bei mehr als einer Partition die Metadaten (raid1) und teilt die Daten auf beide Devices auf (raid0).

Damit btrfs alle zusammengehörigen Partitionen automatisch finden kann, erhalten sie die selbe UUID und unterschiedliche Sub-UUIDs:

$ sudo blkid /dev/sdd1 /dev/sde1
/dev/sdd1: LABEL="mediafiles" UUID="243efbc4-5f72-4352-9160-d693b3ed41b5" UUID_SUB="0a5b948d-9761-4c94-8f85-c9548f1149f2" TYPE="btrfs"
/dev/sde1: LABEL="mediafiles" UUID="243efbc4-5f72-4352-9160-d693b3ed41b5" UUID_SUB="66fbc6c1-8295-476a-bdfe-72536f0b50ed" TYPE="btrfs"

Dementsprechend reicht es beim Mounten auch aus, entweder eines der beiden Devices oder die UUID anzugeben. Die folgenden drei Befehle sind also identisch zueinander:

$ mount /dev/sdd1 /mnt
$ mount /dev/sde1 /mnt
$ mount UUID=243efbc4-5f72-4352-9160-d693b3ed41b5 /mnt

Der Befehl ‘btrfs filesystem show’ zeigt alle erkannten Dateisysteme an:

$ sudo btrfs filesystem show
Label: 'mediafiles'  uuid: 243efbc4-5f72-4352-9160-d693b3ed41b5
        Total devices 2 FS bytes used 809.82GB
        devid    1 size 1.82TB used 817.03GB path /dev/sdd1
        devid    2 size 1.82TB used 817.01GB path /dev/sde1

Btrfs v0.19-102-g2482539

Es gibt jedoch eine kleine Stolperfalle. Soll das RAID-1-btrfs beim Booten automatisch eingehängt werden, so *müssen* alle Devices in der /etc/fstab eingetragen werden. Ansonsten meckert das System, da es nicht alle dazugehörigen Devices selbst finden kann, selbst wenn die UUID verwendet wird:

UUID=19aa7588-9694-4440-ae33-e5b8dc4030fa /media/mediafiles btrfs device=/dev/sdd1,device=/dev/sde1 0 0

Gefährlich ist dies vor allem bei Headless-Systemen, da im laufenden Betrieb die automatische Erkennung der Devices durchaus funktioniert und ein Eintrag ohne die ‘device=’-Optionen daher beim Testen durchaus funktionieren würde.

Nicht ganz einfach ist übrigens die Größe bzw. der freie Speicher des RAID-1-Dateisystems zu ermitteln:

$ df -h /media/mediafiles
Dateisystem            Größe Benut  Verf Ben% Eingehängt auf
/dev/sdd1             3,7T  1,6T  2,1T  44% /media/mediafiles

‘df’ zählt hier also einfach den gesamten und belegten Speicher aller Einzelpartitionen zusammen. Der Grund hierfür liegt, soweit ich das im Wiki verstanden habe, in einem Berechtigungsproblem: Um das Dateisystem als RAID-1 zu erkennen und die Größe damit korrekt anzugeben müsste df direkt darauf zugreifen, was ihm aber zumindest als normaler User nicht erlaubt ist. btrfs bringt daher sein eigenes ‘df’ mit:

$ sudo btrfs fi df /media/mediafiles
Data, RAID1: total=815.00GB, used=808.73GB
Data: total=8.00MB, used=0.00
System, RAID1: total=8.00MB, used=120.00KB
System: total=4.00MB, used=0.00
Metadata, RAID1: total=2.00GB, used=1.09GB
Metadata: total=8.00MB, used=0.00

Das Tool btrfs wird auch verwendet, um weitere Devices zum Raid hinzuzufügen, zu entfernen, Snapshots anzulegen oder das FS zu defragmentieren. Hiermit habe ich bisher aber noch nicht experimentiert, ggf. wird’s einen Nachtrag geben. Erstmal werde ich nun das Verhalten im MythTV-Betrieb beobachten und vor allem auf die – subjektive – Performance im Vergleich zu ext4 achten.

Links:

When doing MVC programming in Java, there is a problem that most people don’t know about. I’ve ignored it myself much too long. The problem is that when you bind a model class to an UI component you will get a giant memory leak.

What happens?

Well, imagine a model class supporting listening for property changes. A simple example might look like this (I extend from PropertyChangeSupport here so that I don’t have to delegate all the methods, normally you wouldn’t do so, of course):

public class Model extends PropertyChangeSupport {
    private String name;
    public Model(String name) {
        super(new Object()); // Only an example! Don't do this in RL!
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        firePropertyChange("name", this.name, this.name = name);
    }
}

Next, imagine a view for this model class. It has an input field that is binded in both direction with the model (very simplified example here, I normally don’t code this way ;-) ):

public class ModelView extends JPanel {
    public ModelView(final Model model) {
        super(new BorderLayout());
        add(new JLabel("Name: "), BorderLayout.WEST);

        final JTextField textfield = new JTextField(model.getName());
        add(textfield, BorderLayout.CENTER);

        // Bind textfield => model (harmless)
        textfield.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                model.setName(textfield.getText());
            }
        });

        // Bind model => textfield (introduces memory leak)
        model.addPropertyChangeListener("name", new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
                textfield.setText(model.getName());
            }
        });
    }
}

From now on we have a memory leak, because the JPanel, the JLabel and the JTextField (and all other referenced) objects will never be removed by the garbage collector as long as the model exists (which might be until the applications end of life). The reason is that the anonymous inner PropertyChangeListener instance has (and must have!) an implicit reference to the JPanel. And even if you replace it by a static class it does have to know the textfield which is a child object of the panel and has a reference back to it. So even if nobody else references the panel the garbage collector sees:

  Model => PropertyChangeListener => JPanel

There is a little known class called WeakReference (and his brother WeakHashMap). It contains an object, but the object could still be removed by the garbage collector as long as there is no other (non-weak) reference to it.

A naive idea is to just encapsulate the PropertyChangeListener within a WeakReference object:

public class WeakListener implements PropertyChangeListener {
    private final WeakReference<PropertyChangeListener> listener;
    public WeakListener(PropertyChangeListener listener) {
        this.listener = new WeakReference<PropertyChangeListener>(listener);
    }

    public void propertyChange(PropertyChangeEvent e) {
        PropertyChangeListener l = this.listener.get();
        if (l != null) {
            l.propertyChange(e);
        }
    }
}

Code in ModelView constructor:

// Bind model => textfield (with little memory leak)
model.addPropertyChangeListener("name", new WeakListener(new PropertyChangeListener() {
    public void propertyChange(PropertyChangeEvent e) {
        textfield.setText(model.getName());
    }
}));

The idea is that you still have this simple and small WeakListener object within your model’s listener list, but the really big part (the original listener, the panel, label, textfield, etc) could be free’d. Sadly, this will not work, because as soon as you gave the anonymous PropertyChangeListener to WeakListener’s constructor nobody else does reference to it, so the garbage collector will remove the object immediately.

The trick is to create a single reference to it which belongs the parent object:

public class ModelView extends JPanel {
    private PropertyChangeListener modelTextfieldListener;

    public ModelView(final Model model) {
        super(new BorderLayout());
        add(new JLabel("Name: "), BorderLayout.WEST);

        final JTextField textfield = new JTextField(model.getName());
        add(textfield, BorderLayout.CENTER);

        // Bind textfield => model (harmless)
        textfield.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                model.setName(textfield.getText());
            }
        });

        // Bind model => textfield (with little memory leak)
        model.addPropertyChangeListener("name", new WeakListener(modelTextfieldListener = new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
                textfield.setText(model.getName());
            }
        }));
    }
}

That’s it. To make this easier I’ve created a little support class WeakListenerSupport that’s very helpful if you have to deal with multiple input-property-bindings. Also it tries to remove (”unlink”) itself from the model if the listener doesn’t exist any longer. It even allows to unlink all weak listeners from a single object.

With this class the above example would look like:

public class ModelView extends JPanel {
    private final WeakListenerSupport wls = new WeakListenerSupport();

    public ModelView(final Model model) {
        super(new BorderLayout());
        add(new JLabel("Name: "), BorderLayout.WEST);

        final JTextField textfield = new JTextField(model.getName());
        add(textfield, BorderLayout.CENTER);

        // Bind textfield => model (harmless)
        textfield.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                model.setName(textfield.getText());
            }
        });

        // Bind model => textfield (without memory leak)
        model.addPropertyChangeListener("name", wls.propertyChange(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
                textfield.setText(model.getName());
            }
        }, model));
    }
}

I’m doing some end-user support for Linux desktops (family and friends). From a chat with my mother and observation of our trainee I’ve noticed that what’s normal users making the most head pains are the different packaging formats. For example, when you want to download Google Chrome Linux users are confronted with four different options:

  • 32-Bit-DEB
  • 64-Bit-DEB
  • 32-Bit-RPM
  • 64-Bit-RPM

Sometimes there are even different .deb’s or .rpm’s for multiple systems (Debian/Ubuntu, Fedora/OpenSuSE/Mandriva, …). And of course there are package managers that have a fundamentally different design philosophy (emerge or ABS).

Even if the requested package could be found in the distributions package repository the very first step for new linux users is: Google the vendors homepage and click “download”. As I don’t think there will ever be a “one and only” package manager for all distributions maybe we should start thinking about some kind of “meta-package-format” (MPF) that’s a simple text file which contains parsable information about plattform specific packages. Some kind of computer readable download page. I think of it as an INI file with various sections and conditions that have to match. The first section that matches all conditions takes it.

A short example how this might look like:

[Ubuntu 11.04/64]
vendor=Ubuntu
version=11.04
arch=x86_64
package=http://www.example.org/dist/myprogram-x.y.z-ubuntu-x86_64.deb

[Ubuntu 11.04/32]
vendor=Ubuntu
version=11.04
arch=i386|i586|i686
package=http://www.example.org/dist/myprogram-x.y.z-ubuntu-i386.deb

[Generic deb/64]
format=deb
arch=x86_64
package=http://www.example.org/dist/myprogram-x.y.z-x86_64.deb

[Generic deb/32]
format=deb
arch=i386|i586|i686
package=http://www.example.org/dist/myprogram-x.y.z-i386.deb

[Fedora]
# Can be found in regular repository
vendor=Fedora
package=myprogramm

[Generic rpm/64]
format=rpm
arch=x86_64
package=http://www.example.org/dist/myprogram-x.y.z-x86_64.rpm

[Generic rpm/32]
format=rpm
arch=i386|i586|i686
package=http://www.example.org/dist/myprogram-x.y.z-i386.rpm

[Gentoo]
format=ebuild
package=http://www.example.org/dist/myprogram-x.y.z.ebuild

[Windows/32]
vendor=Microsoft
os=Windows
arch=i386
package=http://www.example.org/dist/myprogram-x.y.z-i386.exe

[Windows/64]
vendor=Microsoft
os=Windows
arch=x86_64
package=http://www.example.org/dist/myprogram-x.y.z-x86_64.exe

[OS-X]
vendor=Apple
os=OS X
package=http://www.example.org/dist/myprogram-x.y.z.dmg

[Fallback]
package=http://www.example.org/dist/myprogram-x.y.z.tar.gz

Now all that you have to do is to provide this MFP file for download. The MFP manager will evaluate the conditions, download the sufficient package format and give it to the system dependent package manager.

What do you think about this? Am I reinventing the wheel? Is it just a 15th standard? Or is this the idea that helps end users to get in touch with the various linux distributions out there?

Edit: Inserted examples for other OS

Wie bekannt und auch hier im Blog schon beschrieben funktioniert der Broadcom-WLAN-Chip im Lenvo Ideapad U160 unter Linux nicht. Die Karte wird wahlweise durch Softblock oder die Hardblock behindert.

Durch einen Bugreport-Eintrag von Ross Patterson habe ich die Lösung gefunden, auch wenn es bei mir eine andere Reihenfolge brauchte als bei ihm.

Das Problem ist wohl der acer_wmi-Treiber, der die Steuerung der WLAN-Karte stört, aber offenbar irgendetwas initialisiert, wodurch es nach dem Laden und Entladen des Moduls funktioniert.

Da ich gerade nicht viel Zeit habe hier die Kurzfassung für Fedora 15:

1. Die Pakete “broadcom-wl” und “kmod-wl” installieren.

2. Eine neue Datei unter /etc/modprobe.d/acer_wmi mit folgendem Inhalt anlegen:

blacklist acer_wmi
blacklist brcm80211

install wl /sbin/modprobe --ignore-install wl; /sbin/rfkill unblock all; /sbin/modprobe acer_wmi; /sbin/rmmod acer_wmi; /sbin/rfkill unblock all

Seit dieser Änderung funktioniert es für mich zuverlässig. Es muss tatsächlich zweimal “/sbin/rfkill unblock all” drin stehen, mit nur einem Aufruf klappt es nicht.

Wer seinen WLAN-Chip gegen eine Intel-Karte ausgetauscht hat, der kriegt sie mit der selben Änderung zum Laufen, ersetzt jedoch “wl” durch “iwlagn”.