Java: process http.proxyUser and http.proxyPassword
20. April 2012
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!
Evaluate structured code in JasperReports
13. Januar 2012
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 with background color
1. Dezember 2011
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));
BTRFS im RAID-1-Modus im praktischen Einsatz
14. November 2011
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:
Java: Model-View-Controller without memory leaks
7. Oktober 2011
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));
}
}
A generic meta packaging format for linux distributions?
30. August 2011
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
WLAN mit Lenovo U160 unter Linux
15. August 2011
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”.