Physikalisch und virtualisiert bootfähiges Linux

Motivation

Viele Leute tragen ständig ihren Rechner mit sich herum. Nicht immer ist es nur das Telefon, sondern gerne auch das Tablet oder ein Laptop. Mir ist das zu schwer. Ich habe einen USB-Stick bei mir, auf welchem mein tragbares Ubuntu installiert ist. Auf die meisten Rechner, mit denen ich arbeite, habe ich ohnehin vollen Zugriff, sodass ich problemlos von dem externen Datenträger starten lassen kann. Auch bei Freunden kann ich mein System verwenden, sodass ich kein Programm auf einem fremden Rechner installieren muss, nur damit ich es dort einmal benutzen kann. Der Browser meiner Wahl mit meinen lieblingseinstellungen ist immer bei mir, ich brauche nie auf möglicherweise verseuchten Windows-Kisten mein Passwort eingeben. Es halte das für praktisch.

Anders sieht es in der Uni aus. Dort habe ich sehr eingeschränkte Benutzerrechte. Die Installation von Programmen ist mir nicht gestattet, das starten von externen Medien konsequenterweise auch nicht. Allerdings ist aus ganz anderen Gründen Virtualisierungssoftware installiert. Der VMware Player erlaubt mir das anlegen neuer virtueller Maschinen, in denen ich mein Ubuntu im Prinzip starten könnte, jedoch darf nur ein Administrator direkt auf ganze physikalische Laufwerke zugreifen.

Zielsetzung

Ich suche eine Lösung, welche mir erlaubt, das physikalisch bootbare Ubuntu auf meinem USB-Stick auch als eingeschränkter Benutzer in einer virtuellen Maschine starten zu können. Dabei sind für mich diese Virtualisierungslösungen interessant:

Qemu Kompilate für Windows sind auf http://qemu.weilnetz.de/ zu finden. Qemu unterstützt unter Windows zwar keine Beschleunigung durch hardwaregestützte Virtualisierung, lässt sich aber ohne Installation und mit minimalen Benutzerrechten ausführen. Für meinen Zweck kann ich es besser nutzen als Portable-VirtualBox, da VirtualBox offenbar zwingend die Installation von Treibern und Diensten erfordert.

Dateien und Partitionen

Nur Administratoren dürfen direkt blockweise auf Datenträger zugreifen, da sich sonst alle Zugriffsbeschränkungen des Dateisystems umgehen ließen. Ich brauche also eine Lösung, welche mir erlaubt, über das Dateisystem mit einfachen Benutzerrechten auf einen ganzen Datenträger zuzugreifen. An dieser Stelle kommen die aus der Virtualisierung bekannten Festplattenabbilder ins Spiel. Allerdings will ich nicht zwei Installationen des gleichen Systems auf dem Stick haben. Genau betrachtet benötige ich auch keinen direkten Zugriff auf den gesamten Datenträger. Die Ubuntu root Partition enthält alle relevanten Daten (bei mir sind das auch /boot und /home). Dabei sollte folgendes nicht vergessen werden: Eine Partition ist nichts anderes als ein zusammenhängender Bereich fester Position und Größe auf dem Datenträger. Eine Datei ist auch nichts anderes als ein möglicherweise zusammenhängender Bereich auf einer änderbaren Position und variabler Größe. Glücklicherweise wird aus Performanzgründen die physikalische Position einer Datei auf dem Datenträger selten geändert. Die Größe kann sehr wohl und häufig geändert werden; Virtualisierungswerkzeuge tun dies in Abhängigkeit vom Typ des Festplattenabbildes jedoch nicht. Bleibt also nur noch sicherzustellen, dass die Datei zusammenhängend, also nicht fragmentiert ist. Eine im NFTS defragmentiert vorliegende Datei ist tatsächlich linear zusammenhängend auf dem Datenträger abgelegt. [Beleg benötigt] Das Dateisystem fügt keine Header oder Metainformationen zwischen den Nutzdaten ein. [Beleg benötigt] Es sollte daher möglich sein, eine Datei zu erzeugen, welche sowohl in einem Dateisystem auf einer pyhsikalischen Partition gespeichert ist und dabei gleichzeitig eine virtuelle und physikalische Partition beinhaltet.

image/svg+xml MBR Bootloader Partitionstabelle Partition 1 NTFS Festplattenabbild MBR Partition 2 EXT3 Ubuntu Partition 1

Partitionieren

Beginne mit einem leeren, außreichend großen USB-Stick. Im folgenden wird traditionelle MBR (msdos) Partitionierung verwendet. Entferne gegebenenfalls vorhandene GPTs (bedenke sowohl das Original hinter dem MBR als auch die Sicherungskopie am Ende des Datenträgers). Hierbei hilft gdisk. Ich gehe davon aus, dass ein Datenträger mit 512 Byte großen Sektoren verwendet wird. Lege eine neue Partitionstabelle an. Es gebe nur eine primäre Partition. Traditionell beginnt sie bei Sektor 2048. Formatiere diese Partition mit NTFS, damit Windows sie problemlos Lesen kann. exFAT wäre auch möglich, habe ich aber nicht getestet.

Virtuelle Festplatte anlegen

Wenn das Ubuntu mit VirtualBox oder VMWare virtuell gestartet werden soll, ist es ratsam, das Festplattenabbild gleich im richtigen Format anzulegen. Hierfür bietet sich VMDK an, weil es mit allen oben gennanten Virtualisierungswerkzeugen kompatibel ist. [1] Wer ausschließlich Qemu verwenden will, kann Contig verenden (siehe unten). Die VirtualBox Dokumentation zeigt, wie es geht:

VBoxManage createhd --filename Ubuntu.vmdk --size 6000 --format VMDK --variant Fixed

Hierdurch wird ein Festplattenabbild im VMDK Format angelegt. Es hat eine feste Größe ("fixed") von ungefähr 6 GB. Dieses Festplattenabbild besteht aus zwei Dateien. Einer .vmdk Datei mit Metainformationen und einem Verweis auf das eigentliche Festplattenabbild in einer -flat.vmdk Datei. Diese Datei verhält sich wie ein einfaches, direktes, rohes ("raw") Festplattenabbild. [Beleg benötigt]

Da der USB-Stick leer und das Dateisystem frisch angelegt wurde, könnte die Datei bereits zusammenhängend erzeugt worden sein. Je größer die Datei, desto wahrscheinlicher ist es, dass sie fragmentiert wurde. Das Festplattenabbild muss aber defragmentiert sein. Dies kann mit dem Windows-Werkzeug Contig bewerkstelligt werden:

\> contig Ubuntu-flat.vmdk

Contig v1.7 - Makes files contiguous
Copyright (C) 1998-2012 Mark Russinovich
Sysinternals - www.sysinternals.com
Processing Ubuntu-flat.vmdk...
Ubuntu-flat.vmdk was optimized to 1 fragment.
Summary:
     Number of files processed   : 1
     Number of files defragmented: 1
     Average fragmentation before: 1 frags/file
     Average fragmentation after : 1 frags/file

Alternative: Ist bereits eine physikalische oder vituelle Ubuntu Installation zur Hand, kann diese genutzt werden. Von eninem physikalischen System muss übergangsweise eine Kopie erzeugt werden. Ob diese Kopie mit Virtualisierungswerkzeugen, dd oder anders erzeugt wird, ist unerheblich. Es muss am Ende ein rohes, nicht-fragmentiertes Festplattenabbild auf dem USB-Stick liegen.

Alternative: Wer kein VMDK Festplattenabbild braucht, der kann Contig nutzen, um das Festplattenabbild zu erzeugen. Contig kann die leere Datei in einem Schritt gleizeitig anlegen und defragmentieren. Der Konsistenz halber nenne ich auch dieses rohe Festplattenabbild Ubuntu-flat.vmdk.

\> contig -n Ubuntu-flat.vmdk 6000000

Nun beschreibt die Datei ein logisch und physikalsich zusammenhängendes Stück Speicher.

Ubuntu auf virtueller Maschine installieren

Sofern das Festplattenabbild noch leer ist, sollte jetzt Ubuntu installiert werden. Ich habe mich für ein 32 Bit xubuntu in einem EXT3 Dateisystem entschieden (mehr dazu in Weiterführendes). Wichtig ist, dass eine traditionelle MBR Partitionierung gewählt wird. Um es einfach zu halten, verzichte ich auf separate Partitionen für /boot oder /home oder swap. Ich will die Anzahl der Partitionen möglichst gering halten. Außerdem will ich keine erweiterte Partition verwenden, alle Partitionen müssen primäre Partitionen sein. Von denen darf es in der Partitionstabelle des MBR nur vier geben. Der Bootloader GRUB2 wird in den MBR installiert.

Physikalische Partition der virtuellen Festplatte zuordnen

Zuerst ist herauszufinden, wo sich das Festplattenabbild pysikalisch auf dem Datenträger befindet. Dies kann unter Ubuntu mittels hdparm herausgefunden werden:

~$ sudo hdparm --fibmap /media/hermann/stick/portable_ubuntu/Ubuntu-flat.vmdk

/media/hermann/stick/portable_ubuntu/Ubuntu-flat.vmdk:
 filesystem blocksize 4096, begins at LBA 2048; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0    6703360   12994815    6291456

Die physikalische Position einer Datei ändert sich normalerweise übrigens nicht, wenn die Datei umbenannt beziehungsweise auf demselben Datenträger verschoben wird.

Als nächstes wird sfdisk verwendet, um zu bestimmen, wo die Ubuntu Partition innerhalb des Festplattenabbildes beginnt. sfdisk kann nämlich praktischerweise direkt auf rohen Festplattenabbildern arbeiten, ein Schleifengerät ist nicht notwendig.

~$ sfdisk -d Debian-flat.vmdk
# partition table of Debian-flat.vmdk
unit: sectors

Ubuntu-flat.vmdk1 : start=     2048, size=  6289408, Id=83
Ubuntu-flat.vmdk2 : start=        0, size=        0, Id= 0
Ubuntu-flat.vmdk3 : start=        0, size=        0, Id= 0
Ubuntu-flat.vmdk4 : start=        0, size=        0, Id= 0

Die virtuelle Festplatte beginnt nicht unmittelbar mit der ersten virtuellen Partition. Die erste Partition beginnt bei Sektor 2048. Da alle hier betrachteten Festplatten eine Sektorgröße von 512 verwenden, können die Adressen einfach addiert werden:

~$ echo $(( 6703360 + 2048 ))
6705408

Die Länge der Partition bleibt natürlich dieselbe. In diesem Beispiel sind es 6289408 Sektoren.

Die Ausgabe von sfdisk kann auch in eine Datei umgelenkt werden, sodass man die Partitionstabelle bequem ändern und wieder auf den Datenträger zurückschreiben kann:

~$ sudo sfdisk -d /dev/sdx > partitions.txt

partitions.txt enthält nun eine textuelle Beschreibung der Partitionstabelle des USB-Sticks:

# partition table of /dev/sdx
unit: sectors

/dev/sdc1 : start=     2048, size= 15521792, Id= 7
/dev/sdc2 : start=        0, size=        0, Id= 0
/dev/sdc3 : start=        0, size=        0, Id= 0
/dev/sdc4 : start=        0, size=        0, Id= 0

Die Partitionstabelle kann mit Hilfe der oben gewonnenen Erkenntnisse über die Position des Festplattenabbildes so angepasst werden, dass die Partition der virtuellen Festplatte auch als physikalische Partition sichtbar wird:

# partition table of /dev/sdx
unit: sectors

/dev/sdc1 : start=     2048, size= 15521792, Id= 7
/dev/sdc2 : start=  6705408, size=  6289408, Id=83
/dev/sdc3 : start=        0, size=        0, Id= 0
/dev/sdc4 : start=        0, size=        0, Id= 0

Diese Partitionstabelle ist defekt, denn die zweite Partition liegt innerhalb der ersten Partition. Überlappungen der Partitionen sind eigentlich verboten. Allerdings scheint das für den Betrieb in dieser Konfiguration kein von mir getestetes Betriebssystem zu stören. Linux akzeptiert anstandslos beide Partitionen. Windows zeigt sowieso nur die erste Partition auf USB Wechselmedien an, [2] daher ist die Ubuntu Partition für ein laufendes Windows kein Problem. Jedoch akzeptieren einige BIOSe USB Wechselmedien mit mehreren Partitionen angeblich nicht. [3]

Diese Partitionstabelle gefällt sfdisk nicht. Das Einspielen der veränderten Partitionstabelle kann dennoch erzwungen werden:

~$  sudo sfdisk --force /dev/sdx < partitions.txt

partprobe hat hiernach manchmal keinen unmittelbaren Effekt. Das abziehen und wiedereinführen des USB Sticks hilft jedoch. Nun sollte sowohl die eine physikalische Partition mit NTFS Dateisystem als auch die eigentlich virtuelle Partition mit Ubuntu darin sichtbar sein:

~$ sudo blkid
/dev/sdc1: LABEL="stick" UUID="83485CD396DDF421" TYPE="ntfs"
/dev/sdc2: LABEL="fileubuntu" UUID="356e92fc-b8c1-4802-a334-422234a11e93" TYPE="ext3"

Bootloader installieren

Bisher sitzt der Bootloader GRUB2 nur im MBR der virtuellen Festplatte. Es gibt verschiedene Methoden, einen passenden Bootloader in den MBR des echten Datenträgers zu schreiben. Bedenke, dass das Ubuntu in der Partition der virtuellen Festplatte nun gleichzeitig auch direkt in einer Partition des physikalischen Datenträgers installiert ist. Zu diesem Zeitpunkt verhält sich das auf dem USB-Stick installierte Ubuntu also schon wie ein normal installiertes System. Es bieten sich an:

  • eine der Methoden aus dem Ubuntuusers Wiki.
  • mit dd den Bootloader aus dem Festplattenabbild in den physikalischen MBR schreiben.
  • Ubuntu mit anderen mitteln physikalisch starten, beispielsweise mit Hilfe der Super Grub2 Disk. Innerhalb des gestarteten Systems kann dann grub-install /dev/sdx ausgeführt werden, um GRUB2 in den physikalischen MBR zu schreiben.

Ich hatte gerade eine Super Grub2 Disk zur Hand, also verwendete ich diese Methode. Praktisch daran ist, dass jeder GRUB2 (vom Rettungsmedium, vom physikalischen MBR und vom virtuellen MBR) die Ubuntu Partition erkennen kann. Da die fixen Bezeichner wie die UUID im Dateisystem und nicht in der Partitionstabelle festgelegt sind, sieht die Partition für jeden der Bootloader gleich aus. Auch bei einem Kernelupdate wird später nur die eine grub.cfg, welche in der Ubuntu Partition liegt, aktualisiert.

Nun kann das Ubuntu auf dem USB-Stick sowohl physikalisch als auch virtualisiert gestartet werden.

Weiterführendes

Ich habe für dieses Experiment ein 32 Bit System verwendet, da ich mit Rechnern umgehe, welche noch nicht 64 Bit fähig sind. Außerdem sind auch bei Ubuntu die 32 Bit installationen kleiner. Da ich knausrig bin, sind meine USB-Sticks klein und jedes Gigabyte ist wichtig. Für andere Speicherplatzknauser noch ein Hinweis: xubuntu verlangt bei der Installation mindestens 6GB freien Speicherplatz. Ein minimales Ubuntu benötigt weniger, allerdings ist die nachträgliche Installation einer graphischen Oberfläche wie xfce etwas hakelig (ich habe dabei traditionell Schwierigkeiten mit einer unvollständigen PolicyKit Installation). Hier ist Debian freundlicher.

Ich habe außerdem EXT3 gewählt, weil nicht alle Systeme verhindern, dass ein EXT4 Dateisystem mehrmals gemountet wird. Das kann leicht geschehen, wenn das Host-Betriebssystem alle Partitionen des Datenträgers einhängt und ich gleichzeitig das Ubuntu in einer virtuellen Maschine laufen lassen will.

Es gibt Rechner, welche UEFI nutzen, aber kein CSM für den traditionellen Start über den Bootloader im MBR unterstützen. Hier startet mein Stick so nicht. Theoretisch wäre es wohl möglich, nicht nur eine Partition zu erzeugen, welche sowohl physikalisch als auch virtualisiert Zugreifbar ist, sondern gleichzeitig auch noch einen hybriden Datenträger mit MBR und GPT für UEFI Boot zu erstellen. Auch die Macke von Windows, nur die erste Partition eines USB-Wechselmediums anzuzeigen, ist nicht kritisch, da entgegen populärer Meinungen die ESP nur anhand iher GUID erkannt wird, nicht anhand ihrer Position. [4]

Ein 64 Bit UEFI benötigt angeblich zwingend ein 64 Bit Betriebssystem. [Beleg benötigt] Davon unabhängig kann ich interessanterweise problemlos das 64 Bit Kernelabbild der 32 Bit Installation hinzufügen. Der 64 Bit Kernel startet ohne Schwierigkeiten und führt die 32 Bit Programme ohne weiteren Kommentar aus. Es scheint, die Trennung von Kernel und Anwendungen funktioniert hier sehr gut. Ich nehme an, das fällt außeinander, sobald 3D Beschleunigung oder andere Hardware/Treiber/Kernel-nahe Vorgänge notwendig sind. Bis dahin bin ich erstaunt und positiv überrascht.

Nachtrag: Ja, dies ist auch mit GPT möglich. GRUB2 kann dann allerdings nicht direkt im hybriden MBR installiert werden, weil unmittelbar hinter dem MBR kein platz dafür ist. Vielleicht kann auch ein traditioneller MBR Start eine GPT "legacy boot" Partition nutzen. [5] Die hybride Partitionstabelle ist voll:

  1. Partition für Nutzdaten in NTFS
  2. eingebettete Ubuntu Partition
  3. GPT "legacy boot" Partition
  4. ESP

Es bleibt keine MBR Partition mehr übrig, um die primäre GPT zu schützen. Die ESP ist für den Start mittels MBR zwar unerheblich, jedoch will ich die Partitionsdefinitionen synchron halten. Damit das Erstellen der Überlappenden Partition überhaupt möglich ist, musste ich gdisk selbst kompilieren, da ich die Schutzfunktion int GPTData::FindOverlaps(void) ausbauen musste, indem ich an passender Stelle ein return 0 einfügte. Sind auf einem USB Wechselmedium GPT und hybrider MBR vorhanden, scheint Windows die Partitionstabelle des MBR zu bevorzugen. Da wir beide Partitionstabellen bewusst defekt anlegen, kann es sein, dass Linux, welches stets der GPT vorrang gibt, den USB Stick noch verwenden kann, Windows aber nicht, sofern der MBR zu kaputt ist.

[1]http://superuser.com/questions/360517/what-disk-image-should-i-use-with-virtualbox-vdi-vmdk-vhd-or-hdd
[2]http://superuser.com/questions/61487/usb-sticks-and-multiple-partitions
[3]http://www.prime-expert.com/articles/a05/enabling-multiple-partitions-on-removable-usb-storage-devices.php#OtherConsiderations
[4]http://blog.uncooperative.org/blog/2014/02/06/the-efi-system-partition/
[5]http://www.anchor.com.au/blog/2012/10/booting-large-gpt-disks-without-efi/