Das Zurücksichern eines Exchange 2000 Servers mittels NTBackup hat mich einmal mehrere Tage gekostet - und das nur auf Grund eines idiotischen Windows-Fehlers. Im Netz habe ich keine Informationen zu meinem Problem gefunden, zumindest auf meiner Testmaschine war das Problem jedoch reproduzierbar, ebenso meine "Lösung". Vielleicht war es nur die Merkwürdigkeit meines Rechners, vielleicht hilft dieser Text aber auch jemandem, nicht seine Zeit fluchend vor dem Rechner zu verbringen.
Nachdem Exchange fertig installiert ist, soll die NTBackup Online-Sicherung wieder eingespielt werden. Nach der Auswahl des Postfachspeichers (bzw. "Mailbox Store") und der Auswahl des Zielservers für die Wiederherstellung erscheint folgende Fehlermeldung (siehe Bild): "Der angegebene Computer ist kein Microsoft Exchange-Server oder die Microsoft Exchange-Dienste wurden nicht gestartet."
Die Fehlermeldung ist falsch, Exchange läuft auf dem Rechner wunderbar - nur eben ohne Daten. Die Backupdatei selbst ist unbeschädigt und die ursprüngliche Sicherung lief ohne Probleme durch. Die Sprachversion und die eingespielten Aktualisierungen sind auf beiden Rechnern (Produktivsystem, Restore-System) identisch.
Die einzige Möglichkeit, die bei mir funktioniert hat, war folgende: Zunächst wird vom frisch installierten Exchange ein Backup mittels NTBackup gemacht - hierbei müssen nur die Exchange-Daten ausgewählt werden (Systemzustand etc. und andere Dateien sind zunächst unwichtig). Ebenso ist unwichtig, wo die Sicherung gespeichert wird. Nach erfolgreichem Durchlaufen der Datensicherung kann die Backup-Datei auch sofort entsorgt werden.
Wenn nun NTBackup erneut gestartet wird, erkennt es auf wundersame Weise die ursprüngliche Sicherungsdatei und stellt die Daten wieder her. Geschafft!
Neben der oben beschriebenen offensichtlichen Exchange-Idiotie gibt es noch drei wichtige Punkte:
Es gibt Situationen, in denen man ein laufendes System nachträglich noch mit einem RAID ausrüsten will, um einen besseren Schutz vor dem Ausfall einer Festplatte zu haben. Auf dieser Seite geht es jetzt nur um Software-RAIDs, da dies (insbesondere bei Verwendung von RAID 1) für die meisten Anwendungsfälle ausreicht.
Früher (in den 90ern) war ein RAID-Sytem eigentlich immer mit zusätzlicher Hardware in Form eines RAID-Controllers verbunden. In dieser Erweiterungskarte (häufig SCSI) war die RAID-Funktionalität implementiert, das Betriebssystem "sah" dann nur noch eine große Festplatte. Meist besaß ein solcher RAID-Controller auch ein eigenes BIOS. Ein Vorteil dieser RAID-Controller war, dass alle Rechenoperationen durch die zusätzliche Hardware durchgeführt wurden, so dass die CPU entlastet wurde.
Heutzutage bringen immer mehr Mainboards "RAID-Fähigkeiten" mit. Tatsächlich wird aber eigentlich immer ein zusätzlicher Treiber benötigt, in dem dann die RAID-Funktionalität steckt. Daher entlasten solche Mainboards die CPU gar nicht. Weiterhin sind immer spezielle Treiber notwendig, die unter Linux entweder gar nicht verfügbar oder schlecht getestet sind, weil nicht so viele Benutzer Mainboards eines speziellen Typs verwenden. Zusätzlich kann sich noch das Problem ergeben, dass der Treiber ein eigenes Datenformat für die Festplatte mitbringt. In diesem Fall wird der Ausfall des Mainboards zu einem größeren Schlamassel, da man an die Daten nur mit einem exakt baugleichen "RAID-Chipsatz" herankommt. Ein Software-RAID unter Linux bietet da hingegen die Gewissheit, dass die Datenformate offengelegt sind und viele Rettungsdisks auch Software-RAIDs unterstützen.
Ähnliches gilt übrigens auch für "RAID-Controller", die für 50-100 Euro separat verscherbelt werden. Wirkliche Entlastung der CPU bringen diese meist nicht. Wie so oft erkennt man echte RAID-Controller daran, dass sie etwas teurer sind (ab ca. 200 Euro/Stand August 2006). Die c't hat in der Ausgabe 10/2006 auf den Seiten 186-196 einen größeren Test dazu ("Geballte Plattenpower: 12 SATA-II-RAID-Adapterkarten mit PCI, PCI-X und PCIe", Boi Feddern).
Wirklich lohnen tut sich ein eigenständiger RAID-Controller aus meiner Sicht nur für Anwender, die ein RAID 5 bei relativ hoher Serverlast aufsetzen wollen.
Es gibt im Netz schon diverse Anleitungen zu diesem Thema. Ich habe aber noch eine eigene geschrieben, weil mir an den meisten immer eine oder mehrere Dinge nicht gefallen haben. Diese Anleitung wurde mit CentOS 4 getestet, sollte aber prinzipiell mit allen modernen Linux-Distributionen funktionieren. Weiterhin ist diese Anleitung auch für Rechner nutzbar, bei denen kein physikalischer Zugriff besteht (z.B. sog. "Rootserver").
Ich möchte aber die Vorlagen für diese Anleitung nicht unter den Tisch kehren:
Eine vielleicht interessante Erweiterung wäre noch die Verwendung von LVM. Allerdings hatte dies für mich keine Priorität, da die Partitionsgröße sich sehr wahrscheinlich nie wieder ändern wird (Rootserver) und ich derzeit keinen akuten Bedarf für LVM-Snapshots habe.
Das Allerwichtigste bei diesem Prozess ist ein vollständiges und funktionsfähiges Backup. Einerseits können in dieser Anleitung durchaus Fehler enthalten sein, zum anderen kann einfach irgendetwas passieren (z.B. ein Vertipper bei mkswap) und alle Daten sind weg! Außerdem sollte man sich auch sicher sein, dass das Backup wirklich funktionsfähig ist. Es gibt hunderte Geschichten im Netz, wo dann die Beteiligten nach Eintritt des Ernstfalls feststellen mussten, dass jahrelang nur kaputte Bits gesichert wurden.
Ich gehe im folgenden davon aus, dass im System zwei Festplatten vorhanden sind (hda, hdc), wobei eine davon komplett frei ist (hdc). Außerdem können insbesondere Fehler bei der grub-Konfiguration das System in einem nicht mehr startfähigen Zustand hinterlassen. Für solche Gelegenheiten ist ein Rettungsystem, wie es bei den meisten Hostern zu finden ist, sehr nützlich!
Es ist nicht notwendig, dass beide Platten gleich groß sind, da mdadm sich nur mit Partitionen und nicht mit Festplatten beschäftigt. Folglich müssen nur die gespiegelten Partitionen exakt gleich groß sein.
Ich gehe von folgender Partitionierung aus: Sowohl '/' als auch '/var' und SWAP sind jeweils auf einer gesonderten Partition abgelegt.
Zunächst werden alle für Partitionen RAID-Devices mit einer fehlenden Platte auf der neuen Festplatte hdc angelegt. Für jede Partition (inkl. SWAP) ruft ihr mdadm wie folgt auf:
/sbin/mdadm --create /dev/md0 --level 1 --raid-devices=2 missing /dev/hdc1
Natürlich dürfen nicht immer md0 und hdc1 verwendet werden, sondern bei zweiten Mal md1 und hdc2 etc.
Dabei muss natürlich mdadm installiert sein. Bei CentOS/Fedora heißt das dazugehörige Paket sinnigerweise ebenfalls "mdadm".
Nachdem die RAID-Devices angelegt wurden, erzeugt man darauf das gewünschte Dateisystem, z.B. mit
/sbin/mkfs.ext3 /dev/md0 # fuer die root-Partition /sbin/mkfs.ext3 /dev/md1 # fuer /var /sbin/mkswap /dev/md2 usw.
Gegebenenfalls mit tune2fs die Dateisystemparameter anpassen, z.B.:
tune2fs -c 0 -i 0 /dev/md0
Prinzipiell bringt es eigentlich keinen Vorteil, auch die SWAP-Partition zu spiegeln, da swap-Daten eigentlich nicht mehrfach parallel von der Platte gelesen werden (in diesem Fall kann ein RAID 1 eine Geschwindigkeitssteigerung bringen). Das entscheidende Argument für mich war die Datensicherheit: Wenn eine Platte mit der SWAP-Partition während des Betriebs ausfällt und zu dieser Zeit RAM ausgelagert war, sind diese Daten verloren. Die Folge ist ein undefinierter Systemzustand, weil im Prinzip Teile des RAMs mit einem Mal verloren sind. Daher habe ich mich entschieden, auch die SWAP-Partition zu spiegeln.
Zwischen dem Kopieren der Daten und dem notwendigen Neustart sollten möglichst keine Daten geschrieben werden, da diese sonst verloren sind. Daher würde dazu raten, Dienste wie Mailserver, Webserver und Datenbank herunterzufahren, um versehentlichen Schaden abzuwenden.
Anschließend werden alle Daten auf die neuen RAID-Partitionen kopiert. Dazu müssen diese erst mal gemountet werden:
mount /dev/md0 /mnt/ mount /dev/md1 /mnt/var/ ...
Wichtig ist, dass ihr euch beim Mounten von der Wurzel (Rootpartition) zu eventuell auf Unterverzeichnissen gemountete Partitionen wie /var vorarbeitet: Also erst / mounten, dann /var.
Jetzt müssen die Daten noch kopiert werden:
cp --no-dereference --preserve --recursive --one-file-system / /mnt cp --no-dereference --preserve --recursive --one-file-system /var /mnt ...
Automatische Updates durch fstab-sync verhinern:
rm /etc/hal/device.d/50-fstab-sync.hal ln -s /bin/false /etc/hal/device.d/50-fstab-sync.hal
Damit beim nächsten Mal auch gleich vom RAID gestartet wird, muss noch die Datei /etc/fstab angepasst werden. Sie könnte dann in etwa so aussehen:
/dev/md0 / ext3 defaults 1 1 /dev/md1 /var ext3 defaults 1 1 #/dev/hda2 swap swap defaults 0 0 /dev/md2 swap swap defaults 0 0 ...
fstab-sync wieder aktivieren:
rm /etc/hal/device.d/50-fstab-sync.hal ln -s /usr/sbin/fstab-sync /etc/hal/device.d/50-fstab-sync.hal
Hinweis: Mit CentOS 4.4 war dieser Schritt nicht mehr nötig, da mdadm offenbar bereits im initrd vorhanden ist.
Wenn /boot ebenfalls auf einem RAID-device liegt, muss die initial RAM disk (initrd) angepasst werden, so dass darin auch mdadm enthalten ist. Dieser Vorgang muss leider nach jedem Kernel-Update wiederholt werden. Vergisst man das, wird das System nicht mehr starten!
mkinitrd --with=raid1 raid-initrd-`uname -r`.img `uname -r` mv raid-initrd-`uname -r`.img /mnt/boot
Ich verwende "uname -r", um die aktuelle Kernelversion dynamisch zu ermitteln.
Unter openSuSE muss man
mkinitrd -f md -d /dev/md0 cp /boot/initrd* /mnt/boot
ausführen, da der Bootvorgang sonst bei "Waiting for /dev/md0.." stehen bleibt.
Die Alternative zu einer angepassten initrd ist, /boot auf eine normale Partition zu legen. Dann muss man allerdings die Inhalte von /boot auf beiden Platten manuell spiegeln, damit das System im Notfall von beiden Platten starten kann. Die bequemste Möglichkeit ist natürlich, wenn der Distributor bereits mdadm in der von im mitgelieferten initrd bereitstellt, dann ist dieser Schritt unnötig.
Die /etc/grub.conf muss angepasst werden, so dass das System beim nächsten Mal vom RAID-device startet. Die genauen Versionsnummern müssen natürlich gemäß der Ausgabe von "uname -r" angepasst werden.
title CentOS (2.6.9-22.0.1.EL RAID 1) root (hd1,0) kernel /boot/vmlinuz-2.6.9-22.0.1.EL ro root=/dev/md0 initrd /boot/raid-initrd-2.6.9-22.0.1.EL.img
Wichtig ist hierbei "root (hd1,0)" (Start von der RAID-Partition), die korrekte Kernel-Version (hier "2.6.9-22.0.1.EL"), die Angabe der RAID-Partition ("root=/dev/md0") sowie die Angabe der korrekten initrd (Kernel-Version, Software-RAID-Support).
Vorsicht: Ein Fehler in der grub.conf kann das System in einem nicht mehr startfähigen Zustand hinterlassen, so dass ein manueller Eingriff (oder das Starten in einen Rettungsmodus) notwendig wird.
Nachdem alle Arbeiten abgeschlossen sind, ist ein Neustart fällig. Dazu sollten alle RAID-Platten ausgehängt werden und zwar in der umgekehrten Reihenfolge, in der sie gemountet wurden:
... umount /mnt/var umount /mnt/ ... reboot
Wenn das System reibungslos neu gestartet ist (toi, toi, toi...), muss als erstes überprüft werden, ob wirklich alles geklappt hat.
Die Partitionen auf der alten Platte (hda) müssen alle noch einen neuen Typ verpasst bekommen. Dies geschieht einfach mittels
/sbin/fdisk /dev/hda
Der Typ muss auf 0xfd ("Linux raid autodetect") gesetzt werden. Eine typische fdisk-Session könnte so aussehen:
$ t (Typ ändern) $ 1 (# der Partition) $ fd (Typ: Linux RAID autodetect) $ t (...) $ 2 (...) $ fd (...) $ w (Partitionstabelle schreiben)
Jetzt werden die alten Partitionen zum RAID-Array hinzugefügt. Für jede RAID-Partition den folgenden Befehl ausführen (und wieder md0 und hda1 entspr. anpassen!):
/sbin/mdadm --add /dev/md0 /dev/hda1
Dadurch wird automatisch ein resync ausgelöst. Der Fortschritt kann über
cat /proc/mdstat
beobachtet werden. Der resync ist abgeschlossen, wenn hinter jeder RAID-Partition "[UU]" zu sehen ist.
Nachdem das System jetzt von der Raid-Partition bootet, kann jetzt die /etc/grub.conf wieder zu hd0 geändert werden.
title CentOS (2.6.9-22.0.1.EL RAID 1) root (hd0,0) kernel /boot/vmlinuz-2.6.9-22.0.1.EL ro root=/dev/md0 initrd /boot/raid-initrd-2.6.9-22.0.1.EL.img
Außerdem muss grub noch im boot record der zweiten Platte verankert werden. Dies geschieht mittels dem Kommando "/sbin/grub":
$ find /boot/grub/stage1 ... (Es sollte "hd(0,0)" und "hd(1,0)" als Ausgabe kommen.) $ device (hd0) /dev/hda $ root (hd0,0) $ setup (hd0) ... (grub-Erfolgsmeldung) $ device (hd0) /dev/hdc $ root (hd0,0) $ setup (hd0) ... (grub-Erfolgsmeldung) $ quit
Hinweis: Mit CentOS 4.4 war dieser Schritt nicht mehr nötig, da mdadm offenbar bereits im initrd vorhanden ist, entsprechend ist keine Handarbeit mehr nötig!
Nachdem das RAID-System jetzt eingerichtet ist, sollte man sich mit den Optionen von mdadm vertraut machen. Insbesondere die Benachrichtigung bei einer ausgefallenen Platte sollte getestet werden - denn was nutzt einem das beste RAID, wenn eine Platte ausfällt, man dies aber erst merkt, wenn einige Monate später auch die zweite Platte über den Jordan geht?
Außerdem sollte man jetzt noch - wenn möglich - Fehlerfälle testen, d.h. Booten nur mit einer der beiden Platten oder das Verhalten des RAIDs, wenn eine Platte plötzlich verschwindet.
Nicht vergessen werden sollte auch der Eintrag der neuen Platte in die /etc/smartd.conf, damit auch der Status der Platte durch den smartd immer überwacht wird.
Irgendwann wird (mindestens) eine Platte ausfallen. Bei mir sah das im logwatch-Report dann so aus:
Apr 26 04:05:16 hda: dma_intr: status=0x51 { DriveReady SeekComplete Error } Apr 26 04:05:16 hda: dma_intr: error=0x40 { UncorrectableError }, LBAsect=20252932, sector=20252924 Apr 26 04:05:16 end_request: I/O error, dev hda, sector 20252924 Apr 26 04:05:17 raid1: Disk failure on hda2, disabling device. Apr 26 04:05:17 raid1: hda2: rescheduling sector 3866624 Apr 26 04:05:17 raid1: hdc2: redirecting sector 3866624 to another mirror
Hier ist jetzt nicht die ganze Platte komplett gestorben (z.B. Head-Crash), sondern es war "nur" ein Sektor der Platte unlesbar. Das RAID hat den Ausfall abgefangen, aber das RAID läuft jetzt ohne Fehlertoleranz, weil hda2 deaktiviert wurde, wie man schön mit cat /proc/mdstat sieht:
... md0 : active raid1 hdc2[1] hda2[2](F) 8193024 blocks [2/1] [_U] ...
Im Prinzip ist jetzt ein Plattentausch angesagt. Mutige (oder Unvorsichtige) können aber auch versuchen, die Platte einfach wieder zum RAID hinzuzufügen (jede Platte hat ein paar Reserve-Sektoren, die verwendet werden können, nachdem der eigentlich defekte Sektor als unbenutzbar markiert wurde). Dazu wird zunächst die kaputte Partition entfernt und wieder hinzugefügt:
mdadm /dev/md0 -r /dev/hda2 mdadm --add /dev/md0 /dev/hda2
Natürlich lief bei mir nicht alles glatt nach der initialen Einrichtung.
Stellt sicher, dass alle RAID-Partitionen wirklich auch den korrekten Partitionstyp 0xfd haben. Ansonsten wird diese Partition nicht geladen, was dazu führt, dass das System nicht mehr startet, wenn diese Partition beim Systemstart über die fstab eingebunden wird.
Vergleich zwischen dem Original und seinen Abkömmlingen
osCommerce ist einer der bekanntesten freien Online-Shops. Besonders beliebt ist er auf Grund der vielfältigen Erweiterungsmodule und der großen Community. Weiterhin haben sicherlich auch die zahlreichen Dienstleister zum Erfolg beigetragen, die mittlerweile zahlreiche Dienstleistungen rund um osCommerce anbieten.
Trotz der vielfältigen integrierten Funktionen und der vielen Anwender gibt es aber in osCommerce auch sehr deutliche Schwächen:
In den letzten 30 Tagen (20. Mai bis 20. Juni 2006) gab es gerade ganze neun Änderungen im Repository, die allesamt sehr klein waren und auch nur die Übersetzungen betrafen. Es wurden in dieser Zeit also keinerlei Fehler behoben oder neue Funktionen hinzugefügt. Ich mache für die aktuellen Probleme bei der Entwicklung auch die schlechte Code-Qualität verantwortlich, die dafür sorgt, dass Bugfixes Nebenwirkungen haben, es viele Abhängigkeiten gibt und das manuelle Testen einfach Zeit kostet.
Soviel zum Original: Macht xtCommerce es aber besser?
xtCommerce ist eine Abspaltung von osCommerce: Die Macher von xtCommerce haben Mitte 2003 eine Version von osCommerce genommen und selbst weiterentwickelt. Insbesondere sind diverse Erweiterungen von osCommerce direkt im Code integriert, es gibt ein brauchbares Template-System (Smarty) und das System wurde entsprechend den geltenden gesetzlichen Vorschriften umgestaltet.
xtCommerce wird von der xt:Commerce GbR weiterentwickelt, deren Geschäftsmodell insbesondere daraus besteht, dass die aktuelle Version 3.x nur für "Sponsoren" zum Download bereitgestellt wird. Das Sponsor-Dasein kostet dann 98 Euro pro Jahr. Neben dem Download gibt es auch noch spezielle Unterforen, die nur von Sponsoren betreten werden können und in denen angeblich auch die Entwickler Support gewähren.
Technisch gesehen ist xtCommerce auf jeden Fall deutlich weiter als osCommerce in der Standardinstallation. Doch sehe ich auch einige Nachteile:
Absofort ist ein polnisches Sprachmodul für xt:Commerce 3.0.4 SP1 verfügbar. Die Übersetzung des Shops/Admininterfaces wurde in unserem Auftrag durch unseren Partner DialogTicket.com durchgeführt. (Qualitativ Hochwertige Übersetzung durch Muttersprachler). Das Modul ist gegen eine kleine Gebür erhältlich, um weiterhin neue und professionelle Übersetzungen zu finanzieren.
Die zahlreichen Rechtschreibfehler finde ich sehr peinlich ("Absofort", "Hochwertige", "Gebür"), ähnliche Fehler sind mir auch auf weiteren Seiten aufgefallen.
Technisch gesehen ist xtCommerce deutlich fortschrittlicher. Insbesondere das Templatesystem und die bereits integrierten contributions sorgen dafür, dass Aktualisierungen wenigstens etwas einfacher durchzuführen sind.
Rechtlich gesehen lässt sich die xt:Commerce GbR meiner Meinung nach nichts zu Schulden kommen. Allerdings bleibt auf Grund des rüden Vorgehens in den Foren mehr als nur ein kleiner Nachgeschmack, zumal die Weiterverbreitung der Software auf Grund der GPL möglich ist und es auch Seiten gibt, auf denen die Dateien zum Download angeboten werden.
Zudem betreibt die xt:Commerce GbR im Wesentlichen einen Closed-Source-Entwicklungsprozess, kann also von den klassischen Open-Source-Vorteilen nicht profitieren. Die durchgehende Kommerzialisierung von Templates, Contributions und Sprachdateien erhöht die Eintrittsbarriere weiter.
Michael Zanier weist in den Foren auch darauf hin, dass die Entwicklung auch finanziell honoriert werden müsse und inzwischen 80% des Katalog-Codes sich von osCommerce unterscheiden. Ich glaube gerne, dass alle Dateien inzwischen mehrfach verändert wurden (schon die Einführung eines Template-Systems sorgt für sehr viele Änderungen), allerdings sind viele wesentliche Teile nach einer kurzen Recherche meinerseits immernoch die selben. Als Beispiel findet sich hier im Anhang ein Vergleich der Datei checkout_shipping.php. Wie man sieht, hat sich dort wenig geändert. An vielen Stellen hat xtCommerce gleiche bzw. ähnliche Bugs wie osCommerce. Viele der eingebauten contributions existieren auch für osCommerce und wurden ursprünglich von Community-Mitgliedern unentgeltlich unter der GPL zur Verfügung gestellt.
Ich glaube nicht, dass osCommerce in den nächsten 1-2 Jahren xtCommerce ernsthaft herausfordern kann - dafür ist der technische Rückstand schon zu groß. Allerdings gebührt den osCommerce-Autoren wirklich Respekt dafür, dass sie über viele Jahre das System mit großem Einsatz weit gebracht haben. Die von ihnen gewählte GPL sorgt dafür, dass auch kein Unternehmen herkommen und das Produkt vollständig monopolisieren kann.
Andererseits sehe ich durchaus Chancen für einen xtCommerce-Community-Projekt, bei dem die Quellen des jetzigen xt:Commerce verwendet werden. Um marken- und wettbewerbsrechtlichen Problemen zu entgehen, sollte ein eigenes Template entwickelt werden und natürlich müssen auch alle Logos von xtCommerce entfernt werden. Unter einer kompetenten Projektleitung sehe ich dann aber durchaus Chancen für eine gesündere und langfristig profitablere Entwicklung.
Links die osCommerce Version (2.2 Milestone 2), rechts xtCommerce 3.0.4.
// if there is nothing in the customers cart, redirect them t // if there is nothing in the customers cart, redirect them t if ($cart->count_contents() < 1) { | if ($_SESSION['cart']->count_contents() < 1) { tep_redirect(tep_href_link(FILENAME_SHOPPING_CART)); | xtc_redirect(xtc_href_link(FILENAME_SHOPPING_CART)); } } // if no shipping destination address was selected, use the c // if no shipping destination address was selected, use the c if (!tep_session_is_registered('sendto')) { | if (!isset ($_SESSION['sendto'])) { tep_session_register('sendto'); | $_SESSION['sendto'] = $_SESSION['customer_default_add $sendto = $customer_default_address_id; < } else { } else { // verify the selected shipping address // verify the selected shipping address $check_address_query = tep_db_query("select count(*) as t | $check_address_query = xtc_db_query("select count(*) $check_address = tep_db_fetch_array($check_address_query) | $check_address = xtc_db_fetch_array($check_address_qu if ($check_address['total'] != '1') { if ($check_address['total'] != '1') { $sendto = $customer_default_address_id; | $_SESSION['sendto'] = $_SESSION['customer_def if (tep_session_is_registered('shipping')) tep_session_ | if (isset ($_SESSION['shipping'])) > unset ($_SESSION['shipping']); } } } } require(DIR_WS_CLASSES . 'order.php'); require (DIR_WS_CLASSES.'order.php'); $order = new order; | $order = new order(); // register a random ID in the session to check throughout th // register a random ID in the session to check throughout th // against alterations in the shopping cart contents // against alterations in the shopping cart contents if (!tep_session_is_registered('cartID')) tep_session_regis | $_SESSION['cartID'] = $_SESSION['cart']->cartID; $cartID = $cart->cartID; < // if the order contains only virtual products, forward the c // if the order contains only virtual products, forward the c // a shipping address is not needed // a shipping address is not needed if ($order->content_type == 'virtual') { | if ($order->content_type == 'virtual' || ($order->content_typ if (!tep_session_is_registered('shipping')) tep_session_r | $_SESSION['shipping'] = false; $shipping = false; | $_SESSION['sendto'] = false; $sendto = false; | xtc_redirect(xtc_href_link(FILENAME_CHECKOUT_PAYMENT,
Problem: Ein lokal angeschlossener Drucker wird von einem Mac im Netz freigegeben. Ein anderer Mac druckt darauf. Irgendwas geht aber schief, die Datei wird nicht gedruckt. Im Druckmanager von OS x kann der Job zwar gelöscht werden, taucht dann aber sofort wieder auf. Scheinbar ist die einzige Lösung das Löschen und Neuanlegen des Druckers.
Betroffene Systeme: Mac OS X 10.3.x, Mac OS X 10.4.y (mind. bis 10.4.3), vermutlich auch frühere OS X-Versionen.
Hintergrund: Eigentlich löscht der Druckmanager die Jobs gar nicht, diese werden von cups verwaltet und die von einem anderen Rechner aus abgeschickten Jobs darf ein Benutzer gar nicht löschen (cups Sicherheitsfeature). Allerdings hat das Apple-Programm einen Bug, so dass hier keine Fehlermeldung ausgegeben wird.
Lösung: Das Löschen ist nur über das cups-Webinterface (http://localhost:631) möglich. Allerdings werdet ihr beim Löschen eines Jobs standardmäßig eine Fehlermeldung wie "client-error-forbidden" bekommen, weil ihr bei cups nicht angemeldet seid und daher auch keine Jobs löschen dürft. Abhilfe schafft hier ein Eintrag in der /private/etc/cups/cupsd.conf
.
<Location /jobs> # You may wish to limit access to job operations, either with Allow # and Deny lines, or by requiring a username and password. AuthType Basic AuthClass System Allow from 127.0.0.1 </Location>
Anschließend mittels ps aux | grep cups
die Prozess-ID ermitteln, mit kill
cups beenden und mittels cupsd
wieder neu starten (vielen Dank übrigens an Adam Rosi Kessel für diese Lösung). Allerdings können damit nur "Admin"-User sich anmelden bzw. Jobs löschen.
Damit das auch bei allen anderen geht, wird die Gruppe cupsadmins angelegt. Das geht entweder über den Netinfo-Manager oder (wie ich finde einfacher) über die Konsole. Dazu benötigt ihr zwei Skripte: add-group und add-user2group (Dank an die Macher von OSXFAQ.com, die diese Skripte bereit gestellt haben (http://www.osxfaq.com/tips/unix-tricks/week91/thursday.ws, http://www.osxfaq.com/tips/unix-tricks/week91/friday.ws). Diese ladet ihr runter und macht sie ausführbar (chmod 0700 add-*
).
./add-group cupsadmins 137 ./add-user2group cupsadmins <usernamen>
Die Gruppen-ID 137 ist übrigens willkürlich von mir gewählt, vielleicht gibt das später Probleme. Bei mir klappts aber erst mal.
Anschließend muss noch die cupsd.conf wieder angepasst werden und zwar der Eintrag SystemGroup wird um cupsadmins ergänzt, so dass alle Benutzer der Gruppe cupsadmins das cups-System vollständig verwalten können.
Mit MacOS X 10.3 (Panther) gibt es noch weitere Probleme, da hat Apple nochmals Mist gebaut (s. cups-Webinterface kaputt). Bei neueren und älteren Versionen (Jaguar, Tiger) könnt ihr euch zum Glück jetzt erst mal zurücklehnen.
Problem: Ihr versucht euch unter http://localhost:631 ins cups-Webinterface einzuloggen, was aber nicht klappt, da euer Passwort scheinbar nicht akzeptiert wird.
Betroffene Systeme: nur Mac OS X 10.3.x (mind. bis 10.3.9)
Hintergrund: Apple hat Systemschnittstellen geändert, aber das mitgelieferte cups nicht angepasst. Ich finde es höchst ärgerlich und extrem peinlich für Apple, dass sie es bis 10.3.9 nicht für nötig befunden haben, den Bug zu beheben. Für weitere technische Hintergründe verweise ich auf What Password Do I Need to Use in the Web Interface?. Vielen Dank auch an die Forenmitglieder von OSXFAQ, da ich dort einen Ansatzpunkt für das Problem gefunden habe.
Lösung: Wie schon unter cups.org beschrieben, müsst ihr wohl die Passwörter der User auf Basic zurückstellen, da ihr ohne Authentifizierung keine Druckjobs löschen könnt (Problem s.o.).
Die Kernel von RHEL und Centos 4 unterstützen zwar prinzipiell ACLs, allerdings muss die Unterstützung beim mounten der Partitionen auch angeschaltet werden. Ein entspr. Eintrag in der /etc/fstab reicht:
LABEL=/ / ext3 defaults,acl 1 1 LABEL=/var /var ext3 defaults,acl 1 2
Durch einen Neustart oder ein re-mount kommt man in den Genuss der ACLs (mount -o remount,acl /). Durch die Aktivierung von ACLs gehen (AFAIK!) keine Daten verloren bzw. müssen keine weiteren Aktionen durchgeführt werden, sie sind einfach da.
Problem: Ein Anrufer ruft an, es klingelt, doch der Anrufer legt auf, bevor abgenommen wird. Das Telefon klingelt aber ewig weiter. Der Kontext in der extensions.conf sieht aus wie folgt:
[capi-in] exten => _.,1,Dial(Sip/100) exten => _.,2,Hangup
Hintergrund: (Achtung, nur zusammen gereimt, diese Erklärung ist daher vielleicht falsch! ) Asterisk erkennt schon, dass der Anrufer aufgelegt hat. Allerdings wird der aktuelle Kontext erneut durchlaufen, um ggf. noch andere Aktionen auszuführen. Bei der obigen Konfiguration wird in diesem Fall erneut der Teilnehmer 100 angerufen, anstatt aufzulegen!
Lösung: In den Kontext muss noch die hangup-Direktive speziell behandelt werden. Folgende Konfiguration verhindert das aber:
[capi-in] exten => _.,1,Dial(Sip/100) exten => h,1,Hangup
Problem: Ansagen scheinen schon begonnen zu haben bevor der Anrufer etwas hört, d.h. 1/10-1/2 Sekunde fehlt. Dabei macht es keinen Unterschied, welches Telefon verwendet wird (Cisco 7970, Softphone Xten Lite, klassisches Telefon). Auch ist es egal, ob es ein internes Gespräch über SIP, SCCP oder eben POTS ist. Die Definition der Nummer in der extensions.conf sieht z.B. so aus:
exten => 600,1,VoiceMailMain()
Lösung: Für den Einbau einer Verzögerung (hier eine Sekunde) geht man wie folgt vor:
exten => 600,1,Answer exten => 600,n,Wait,1 exten => 600,n,VoiceMailMain()
Vielen Dank an betateilchen, der im IP-Phone-Forum diese Lösung vorgeschlagen hat.
Mit Bacula kann man auch Windowsrechner sichern. Im folgenden geht es um die Besonderheiten, die dabei auftreten können. Ausdrücklich geht es nicht darum, wie man den director oder den storage daemon unter Windows betreibt. Mittels Cygwin sollte das zwar gehen, aber Windows selbst hat meiner Erfahrung nach so viele Probleme, dass eine Unix-Maschine da viel einfacher ist. Erspart euch die Scherereien, nehmt ev. auch einen alten Rechner (solange die Backups an sich sicher sind), packt CentOS drauf und schlaft ruhig.
Manche Programme packen ihre Konfiguration in die Windows Registry. Folglich müssen auch diese Daten gesichert werden. Gleichzeitig will man keinen kompletten Registry-Dump, weil der erstens zu groß ist und zweitens auch so nicht auf komplett anderer Hardware zum Restore genutzt werden kann. Hier hilft das Werkzeug "reg.exe", das auch einzelne Registry-Äste sichern kann und zumindest bei Windows 2000 dabei ist (Support-Verzeichnis auf der Installations-CD). reg.exe schreibt einen Registry-Pfad in eine Datei. Beispiel:
C:\WINNT\system32\reg.exe export "HKU\S-1-5-21-5435165743-156456421-452131213-1000\Software\RIT" thebat.reg
"HKU" steht hierbei für "HKEY_USER". Beachten solltet ihr, dass ihr nicht HKCU nehmen könnt, weil Bacula unter einem anderen Benutzerkonto ("SYSTEM") läuft. Entsprechend müsst ihr diese kryptische Ziffernfolge für den konkreten Benutzer herausfinden (regedit - HKU aufklappen).
Um noch mal alles zusammenzufassen: Ich lege im Bacula-Programmverzeichnis den Ordner "files" an, in dem alle temporären Dateien geschrieben werden. Anschließend gibt es z.B. ein Skript "registry_backup.reg", das etwa so aussieht:
del /Q "C:\Programme\bacula\files\*" cd C:\Programme\bacula\files C:\WINNT\system32\reg.exe export "HKU\S-1-5-21-5435165743-156456421-452131213-1000\Software\RIT" thebat.reg (...)
Mittels der Direktive "ClientRunBeforeJob" wird dann dieses Skript ausgeführt und die Dateien im Verzeichnis "files" werden einfach ganz normal gesichert.
HKCU\Software\SimonTatham
HKCU\Software\Martin Prikryl
HKCU\Software\RIT
Zum Sichern von MS Exchange habe ich einen eigenen Artikel geschrieben: MS Exchange sichern mit Bacula
Seit Version 1.38 können alle Verbindungen zwischen den daemons auch mit TLS verschlüsselt werden. Der Windowsclient unterstützt dies jedoch (noch) nicht.
Anmerkung: Inzwischen wird zumindest bei Fedora das yum-Plugin "installonlyn" automatisch mitgeliefert und aktiviert, so dass die hier beschriebene Vorgehensweise nicht mehr erforderlich ist.
Mit der Zeit sammeln sich auf dem eigenen Rechner durch die diversen Updates immer mehr verschiedene Kernelversionen an und verbrauchen Festplattenplatz bzw. müllen das grub-Bootmenü zu. Man kann die unnötigen Versionen natürlich auch direkt mit yum entsorgen, aber dabei geht schnell auch mal was schief (alle Kernel weg...).
Mit dem Paket yum-utils kann man die gleiche Aufgabe schnell und sicher erledigen.
package-cleanup --oldkernels
entfernt alle alten Kernel bis auf die letzten beiden (und mit der Option --count=KERNELCOUNT
kann man auch das beeinflussen). Die grub.conf wird praktischerweise auch gleich mit angepasst.
Neben diesen Tools gibt es auch noch interessante Plugins für yum. protectbase kann z.B. dafür sorgen, dass selbstkompilierte Pakete (ev. mit speziellen Optionen) aus privaten Repositories nicht durch aktuellere Versionen aus offiziellen Quellen überschrieben werden. fastestmirror testet verschiedene Downloadquellen auf ihre Geschwindigkeit, so dass der Download möglichst schnell von statten geht.
Problem: Bei einer S/MIME-signierten Mail wird nur "ungültige Signatur" angezeigt. Bei einem Doppelklick auf das Icon erscheint die Fehlermeldung "PKCS#7-Objekt kann nicht verarbeitet werden. Nachrichtenüberprüfung fehlgeschlagen. Es liegen keine Informationen über Signaturen vor."
Lösung: Dies ist scheinbar ein Bug bei der S/MIME-Implementation in The Bat! 1.62r. Der Fehler tritt offenbar auf, wenn die Mail mit "KMail/1.9.1" erzeugt wurde. Eventuell liegt das an unterschiedlichen Zeilenenden (\n vs. \r\n) mit denen The Bat! nicht zurechtkommt. Mit einem eigenen Python-Script konnte die Mail aber problemlos verifiziert werden.
Problem: Bei einer S/MIME-signierten Mail wird nur "ungültige Signatur" angezeigt. Bei einem Doppelklick auf das Icon erscheint der Prüfreport für signierte Nachrichten mit dem Status "Übereinstimmungsfehler in Inhaltsübersicht". Mailclient war "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.12) Gecko/20050921".
Weitere Informationen: Mit meinem Python S/MIME-Verifier konnte die Mail ebenfalls nicht (Fehler "2902:error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure:pk7_doit.c:804:2902:error:21075069:PKCS7 routines:PKCS7_verify:signature failure:pk7_smime.c:265:"). Nach einigen Versuchen klappte es dann.