Alle Beiträge von Sebastian Oehl

Udev & Systemd

Das Ziel ist simpel: Wenn eine bestimmte USB Festplatte angesteckt wird, so soll Linux automatisch damit beginnen bestimmte Verzeichnisse auf die USB Festplatte zu kopieren, bzw besser die vorhandene Verzeichnisstruktur der Quelle mit dem Backuplaufwerk abgleichen, sodass nur die Dateien erneut auf das Backup kopiert werden, die seit dem letzten Backup verändert wurden.

Die Umsetzung war dann zumindest für mich deutlich anspruchsvoller als am Anfang geplant. Denn um Aktionen auszuführen, wenn sich etwas am USB Bus tut ist udev zwar das Mittel der Wahl, aber die Skripte die udev startet dürfen laut Manpage „nicht lange laufen“ bzw. werden nach meiner Erfahrung gekillt, wenn sie dennoch lange brauchen. Die Lösung liegt darin, statt eines Scriptes einen Dienst von udev starten zu lassen, welches dann widerum ein Script startet. Aber einen Schritt nach dem anderen:

Gegeben sind 7 USB-Festplatten unterschiedlicher Hersteller. Festplatte1 wurde mit „Montag“ gelabelt, Festplatte 2 mit „Dienstag“, Festplatte 3 mit „Mittwoch“ usw… An jedem Kalendertag wird die zum Wochentag passende Festplatte gesteckt. Mittels udev wird das stecken einer Festplatte erkannt und ein Script ein Dienst gestartet, welcher wiederum ein Shellscript startet, welches das Label der Festplatte mit dem Wochentag abgleicht und bei Übereinstimmung die gewünschte Sicherung anstößt.

Mein Praxisfall bezog sich zwar auf ein NAS mit dem Debian basierten OpenMediaVault, aber das ganze läßt sich 1:1 auf den RaspberryPi übertragen.

Zunächst einmal müssen wir herausfinden, wo sich die noch nicht gemountete Festplatte am Pi versteckt. Alle vom Kernel erkannten Laufwerke (und nicht nur die) sind zunächst einmal in dem Verzeichnis /dev/ aufgelistet. Festplatten werden dabei als „sd*“ eingebunden. Für jede angeschlossene Festplatte existiert ein Eintrag. Für die erste wäre dies „sda“, für die zweite „sdb“ usw. Die Partitionen der Platten werden dann durchgezählt. Sollten also auf der ersten Festplatte drei Partitionen sein, so exitieren 4(!) Einträge:

$ ls -lish /dev/sd*
4513 0 brw-rw---T 1 root floppy 8, 0 Jan  1  1970 /dev/sda
4514 0 brw-rw---T 1 root floppy 8, 1 Jan  1  1970 /dev/sda1
4516 0 brw-rw---T 1 root floppy 8, 1 Jan  1  1970 /dev/sda2
4519 0 brw-rw---T 1 root floppy 8, 1 Jan  1  1970 /dev/sda3

sda steht dabei für die Festplatte an sich, nicht für eine Partition der Festplatte. Die Einträge sda1, sda2 und sda3 geben dann die Partionen der Festplatte an. Für mein Szenario ist jede Festplatte nur mit einer Partition versehen, sodass ich die Einträge in dem Listing oben gerade „dabei geschummelt“ habe.

Da sda1 über USB angeschlossen wurde, läßt sich über udev eine Regel erstellen was passieren soll, wenn dieses USB Device angeschlossen wird.

Moment mal, was zur Hölle ist udev?!?!

Wer das noch nie gehört hat liest sich am besten den Eintrag dazu auf Wikipedia durch. Hier nur das wichtigste von dort zitiert: „udev überwacht und wertet hotplug-Ereignisse aus. Finden sich dort Informationen über ein neu angeschlossenes Gerät, werden zu diesem Gerät vorhandene zusätzliche Informationen dem sysfs-Dateisystem entnommen und eine neue Gerätedatei im /dev-Verzeichnis erzeugt. Dabei ist der für die spezielle Datei verwendete Name und die Zugriffsberechtigung frei durch Regeln konfigurierbar.“ (Quelle: Wikipedia)

Das schöne an udev sind die Regeln die sich damit erstellen lassen. Es bietet die Möglichkeit Geräte nach bestimmten Kriterien zu filtern und Aktionsreglen für diese Filter zu erstellen. Dh. wenn ein Filter auf ein neu angeschlossenes Gerät zutrifft, dann kann zB. Ein Shellscript gestartet werden, dass sich um weitere Arbeiten für dieses Gerät kümmert. Oder z.B. die gewünschte Sicherung anstößt.

Um diese Filter zu erstellen, müssen wir zunächst einmal herausfinden wo sich die Festplatte unter /dev/ eingenistet hat. Also Platte zunächst nochmal abstöpseln und den Befehl von oben erneut ausführen:

$ ls -lish /dev/sd*
 ls: Zugriff auf /dev/sd* nicht möglich: Datei oder Verzeichnis nicht gefunden

Na gut, an meinem RaspberryPi hängt nur die eine echte Festplatte, daher ist das bei mir nicht schwierig, aber bei euch könnten da jetzt noch diverse sda’s, sdb’s bis sde’s oder so vorhanden sein.

Anschließend die Platte wieder anstecken und den Befehl erneut ausführen:

$ ls -lish /dev/sd*
4513 0 brw-rw---T 1 root floppy 8, 0 Jan  1  1970 /dev/sda
4514 0 brw-rw---T 1 root floppy 8, 1 Jan  1  1970 /dev/sda1

Wie gesagt, in meiner Testumgebung gibts gerade nur die eine Festplatte… Daher ist das hier leicht und meine Festplatte befindet sich momentan unter /dev/sda1. (Sie ist dort aber nicht gemounted!)

Nachdem ich nun weiß wo sich die Platte befindet, kann ich über udev eine Fülle an Informationen auslesen lassen (Die Ausgabe erfolgt in Blöcken. Aus Gründen der Lesbarkeit habe ich in dem folgenden Listing einige Blöcke entfernt):

$ udevadm info -a -p $(udevadm info -q path -n /dev/sda1)
 
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
 
  looking at device '/devices/platform/bcm2708_usb/usb1/1-1/1-1.4/1-1.4.3/1-1.4.3:1.0/host1/target1:0:0/1:0:0:0/block/sda/sda1':
    KERNEL=="sda1"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{ro}=="0"
    ATTR{size}=="3907024896"
    ATTR{stat}=="      83        0      664      150        0        0        0        0        0      150      150"
    ATTR{partition}=="1"
    ATTR{start}=="2048"
    ATTR{discard_alignment}=="0"
    ATTR{alignment_offset}=="0"
    ATTR{inflight}=="       0        0"
 
  looking at parent device '/devices/platform/bcm2708_usb/usb1/1-1/1-1.4/1-1.4.3/1-1.4.3:1.0/host1/target1:0:0/1:0:0:0':
    KERNELS=="1:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{rev}=="0   "
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="7"
    ATTRS{model}=="External USB 3.0"
    ATTRS{state}=="running"
    ATTRS{queue_type}=="none"
    ATTRS{iodone_cnt}=="0xcb"
    ATTRS{iorequest_cnt}=="0xcb"
    ATTRS{device_busy}=="0"
    ATTRS{evt_capacity_change_reported}=="0"
    ATTRS{timeout}=="30"
    ATTRS{evt_media_change}=="0"
    ATTRS{max_sectors}=="240"
    ATTRS{ioerr_cnt}=="0x2"
    ATTRS{queue_depth}=="1"
    ATTRS{vendor}=="TOSHIBA "
    ATTRS{evt_soft_threshold_reached}=="0"
    ATTRS{device_blocked}=="0"
    ATTRS{evt_mode_parameter_change_reported}=="0"
    ATTRS{evt_lun_change_reported}=="0"
    ATTRS{evt_inquiry_change_reported}=="0"
    ATTRS{iocounterbits}=="32"
    ATTRS{eh_timeout}=="10"
 
  looking at parent device '/devices/platform/bcm2708_usb/usb1/1-1/1-1.4/1-1.4.3':
    KERNELS=="1-1.4.3"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{devpath}=="1.4.3"
    ATTRS{idVendor}=="0480"
    ATTRS{speed}=="480"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="8"
    ATTRS{configuration}==""
    ATTRS{bMaxPower}=="500mA"
    ATTRS{authorized}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{maxchild}=="0"
    ATTRS{bcdDevice}=="0000"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{serial}=="20140824004767F"
    ATTRS{version}==" 2.10"
    ATTRS{urbnum}=="635"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="TOSHIBA"
    ATTRS{removable}=="unknown"
    ATTRS{idProduct}=="a200"
    ATTRS{bDeviceClass}=="00"
    ATTRS{product}=="External USB 3.0"
 
  looking at parent device '/devices/platform':
    KERNELS=="platform"
    SUBSYSTEMS==""
    DRIVERS==""

😀 Yummy!!

udev gestattet es in seinen Regeln die Kritierien der einzelnen Blöcke zu kombinieren. D.h. alles was im ersten Block ausgegeben wurde kann ich für eine Regel verwenden oder alles was in Block zwei steht. Es ist jedoch nicht möglich Attribute aus Block zwei mit Block eins zu kombinieren. Also möglich ist es schon, bloß wird es nicht funktionieren 😉

In den meisten Anleitungen, die man im Netz findet, werden die Regeln immer auf die Werte der Attribute „Model“, „idVendor“ und / oder „Vendor“ bezogen. Das ist in den meisten Fällen auch gut und richtig. Da ich aber mit Festplatten unterschiedlicher Hersteller arbeite, muss ich etwas allgemeiner bleiben.

Das Anlegen der Regeln erfolgt durch das Anlegen einer Regeldatei in dem Verzeichnis /etc/udev/rules.d/. Und natürlich gibts dort bereits auch einige Regeldateien:

$ ls -lish /etc/udev/rules.d/
insgesamt 12K
25727 4,0K -rw-r--r-- 1 root root 114 Feb 16 14:30 40-scratch.rules
26570 4,0K -rw-r--r-- 1 root root  47 Feb 16 14:10 99-input.rules
 1373 4,0K -rw-r--r-- 1 root root 110 Feb 27 19:46 99-usb-backup-disk.rules

Die Nummerierung ist nicht willkürlich, sondern in dieser Reihenfolge werden die Regeln von udev abgearbeitet. Um nix „durcheinander zu bringen“, sollte eure Regeldatei also nicht gerade mit 10 beginnen. Wie im echten Leben ist es besser sich „Hinten“ anzustellen, und daher ist meine Regeldatei hier die 99-usb-backup-disk.rules geworden.

Die Datei selbst enthält nur eine einzige Zeile mit den Filterkritierien und diversen Aktionen. Ich kann und will hier nicht alle Möglichkeiten wiedergeben die udev bietet. Wer sich tiefer einarbeiten will, sollte google mit dem Begriff „writing udev rules“ füttern und sich von den im Netz gebotenen Anleitungen überwältigen lassen.

Meine Regel soll immer greifen, wenn ein USB Laufwerk angeschlossen wird. Also bezieht sich mein Filter auf Block 3 der obigen Ausgabe (Ob es tatsächlich das gewünschte Sicherungslaufwerk ist soll das Backupscript über das Label der Partition hinterher herausfinden):

SUBSYSTEMS=="usb", DRIVERS=="usb", KERNEL=="sd?1", ACTION=="add"

Subsystem und Driver sind die Werte die aus udev kommen. Das doppelte „=“ ist in dem Fall wichtig, da sonst keine Prüfung, sondern eine unnütze Zuweisung erfolgen würde! Der Parameter KERNEL bewirkt, dass der Filter nur greift, wenn durch das Hotplug -Event ein neues /dev/sdX1 Device angelegt wurde. Den Parameter „Action“ habe ich nicht aus obiger Ausgabe, aber er ist wichtig damit die Regel nur dann greift, wenn das Gerät frisch gestöpselt wurde.

Soweit so gut die Regel. Nun soll ein Script (/home/pi/roboBackup.sh) gestartet werden. Zu Testzwecken halten wir es erstmal extrem simpel:

#! /bin/bash
# /home/pi/roboBackup.sh
log=/home/pi/log.txt
 
echo `date`       > $log
echo Hello World >> $log
echo $1          >> $log
 
exit 0

Das Script tut nicht viel. Es ewartet einen Parameter (nämlich die Device-Datei sdX1) und schreibt diesen in eine Log Datei. Damit das Script aufgerufen wird muss dies nun noch in die udev Regel eingefügt werden und die komplette Datei sieht demnach so aus:

SUBSYSTEMS=="usb", DRIVERS=="usb", KERNEL=="sd?1", ACTION=="add", RUN+="/home/pi/roboBackup.sh %k"

%k ist der gewünschte Parameter welcher das Blockdevice wiedergibt. (siehe zb „man udev“)

Abschließend muss udev noch mit dem Befehl $ sudo /etc/init.d/udev restart neusgestartet werden.

Wenn alles klappt kann nun die Platte erneut gestöpselt werden und es sollte im Heimatverzeichnis die laut roboBackup.sh zu erstellende log.txt vorhanden sein (keine Sorge, es kann durchaus 4 bis 5 Sekunden dauern bis die Datei log.txt erscheint):

$ cat /home/pi/log.txt
Sat Feb 28 09:29:11 CET 2015
Hello World
sda1

Soweit also alles nach Plan… Doch nun kommt der Pferdefuss und das Problem: Dieses Demoscript ist klein, niedlich und funktioniert auch wunderbar. Aber das noch zu erstellende Backup Script wird einige 100 GB an Daten zu sichern haben. Und das jeden Tag. Das Script wird also nicht innerhalb weniger Sekunden abgearbeitet sein, sondern mehrere Stunden laufen. Vor allem wenn man über USB 2.0 sichern muss. Und dazu ist laut manpage der Schalter RUN von udev nicht gedacht:

RUN:
Add a program to the list of programs to be executed for a specific device. This can only be used for very short running tasks. Running an event process for a long period of time may block all further events for this or a dependent device. Long running tasks need to be immediately detached from the event process itself.

Leider liest man im Netz viel zu häufig „schlechte“ Lösungen zu diesem Problem indem z.B. das von udev aufgerufene Shellscript nur das lang laufende Shellscript als Hintergrundprozess aufruft. Das ist aber unsauber und auch nicht die für Linux angedachte Lösung. Der Artikel von Jason Ryan beschreibt schön wie man es denn richtig tun sollte, indem man einen systemd Dienst von udev startet. Dieser Beschreibung fehlt mir nur leider, wie man einen Parameter an dem zu startenden Dienst übergibt.

Hierzu bin ich aber über stackoverflow auf diese Lösong gekommen: „Proper(-ish) way to start long-running systemd service on udev event (device hotplug)

Die Lösung beschreibt allerdings ein komplexeres Problem und daher will ich es im folgenden mit Jason’s Artikel zusammenführen und auf mein kleineres Problem herunterbrechen:

Damit es nicht langweilig wird gilt zunächst einmal festzustellen ob überhaupt systemd von der Distribution verwendet wird. Bei Debian basierten Systemen ist dies nämlich nicht der Fall. Am leichtesten lässt es ich testen indem man den Befehl:  $ sudo systemctl

Wenn systemd nicht installiert ist, kommt einfach nur eine Fehlermeldung und es ist noch das ältere sysv-init installiert. Um sysvinit durch systemd zu ersetzen ist folgender Befehl notwendig. Da die Änderung tiefgreifend ist, sollte man eine Sicherung des Systems haben. Auch die Bestätigung der Installation ist daher etwas ungewöhnlicher als sonst (siehe Zeile 20):

$ sudo apt-get install systemd-sysv
Paketlisten werden gelesen... Fertig
Abhängigkeitsbaum wird aufgebaut.
Statusinformationen werden eingelesen.... Fertig
Die folgenden zusätzlichen Pakete werden installiert:
  libcryptsetup4 libpam-systemd libsystemd-daemon0 libsystemd-id128-0 libsystemd-journal0 systemd
Vorgeschlagene Pakete:
  systemd-gui python-cairo
Die folgenden Pakete werden ENTFERNT:
  fake-hwclock init-system-helpers sysvinit
Die folgenden NEUEN Pakete werden installiert:
  libcryptsetup4 libpam-systemd libsystemd-daemon0 libsystemd-id128-0 libsystemd-journal0 systemd systemd-sysv
WARNUNG: Die folgenden essentiellen Pakete werden entfernt.
Dies sollte NICHT geschehen, außer Sie wissen genau, was Sie tun!
  sysvinit
0 aktualisiert, 7 neu installiert, 3 zu entfernen und 4 nicht aktualisiert.
Es müssen 1.580 kB an Archiven heruntergeladen werden.
Nach dieser Operation werden 3.557 kB Plattenplatz zusätzlich benutzt.
Sie sind im Begriff, etwas potentiell Schädliches zu tun.
Zum Fortfahren geben Sie bitte »Ja, tue was ich sage!« ein.

Nötig ist es nicht, aber ich empfehle einen Neustart nachdem systemd installiert wurde. Anschließend sieht die Ausgabe von systemctl wie folgt aus:

$ sudo systemctl
UNIT                                                              LOAD   ACTIVE SUB       JOB DESCRIPTION
proc-sys-fs-binfmt_misc.automount                                 loaded active waiting       Arbitrary Executable File Formats File System Automount Point
sys-devices-dev:f1-tty-ttyAMA0.device                             loaded active plugged       /sys/devices/dev:f1/tty/ttyAMA0
sys-devices-platform-...2d1-1\x2d1.1-1\x2d1.1:1.0-net-eth0.device loaded active plugged       ec00
sys-devices-platform-...-mmc0:0007-block-mmcblk0-mmcblk0p1.device loaded active plugged       /sys/devices/platform/mmc-bcm2835.0/mmc_host/mmc0/mmc0:0007/block/
sys-devices-platform-...-mmc0:0007-block-mmcblk0-mmcblk0p2.device loaded active plugged       /sys/devices/platform/mmc-bcm2835.0/mmc_host/mmc0/mmc0:0007/block/
sys-devices-platform-..._host-mmc0-mmc0:0007-block-mmcblk0.device loaded active plugged       /sys/devices/platform/mmc-bcm2835.0/mmc_host/mmc0/mmc0:0007/block/
 .
 .
 .
sys-devices-virtual-sound-card0.device                            loaded active plugged       /sys/devices/virtual/sound/card0
sys-devices-virtual-tty-tty0.device                               loaded active plugged       /sys/devices/virtual/tty/tty0
sysinit.target                                                    loaded active active        System Initialization
syslog.target                                                     loaded active active        Syslog
systemd-tmpfiles-clean.timer                                      loaded active waiting       Daily Cleanup of Temporary Directories
 
LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.
JOB    = Pending job for the unit.
 
90 units listed. Pass --all to see inactive units, too.

Als nächstes muss die Datei erstellt werden, welche für das starten des Dienstes per systemd verantwortlich ist:

$ sudo nano /etc/systemd/system/roboBackup@.service

Damit der Dienst einen Parameter entgegennehmen kann, ist das „@“ im Namen der Dienstdatei zwingend notwendig! Der Dienst heißt zwar roboBackup.service, wird von udev dann aber durch das @ zu dem jeweiligen Device zugeordnet. Somit läuft roboBackup dann zb. bei sda1 als roboBackup@sda1.service. Wenn eine zweite Festplatte angesteckt würde, während das erste Script noch läuft, so würde wieder roboBackup gesartet. Dann aber als roboBackup@sdb1.service. Beide Dienste würden unabhängig voneinander und eigentständig eine Sicherung auf ihre jeweils von udev zugeteilte Festplatte durchführen.

Der Inhalt von roboBack@.service ist erfreulich übersichtlich:

[Unit]
Description=roboBackup ausfuehren
 
[Service]
ExecStart=/home/pi/roboBackup.sh %I
 
[Install]
WantedBy=system.device

Der Parameter %I sorgt dafür das der Parameter des Dienstes (sdbX1) als Parameter an das auszuführende Shellscript übergeben wird.

Nun muss noch die udev Regeldatei angepasst werden, dass statt des direkten Shellscripts mittels RUN nun der Dienst aufgerufen wird. Also wird der Teil mit RUN ersetzt und die udev Regeldatei sieht nun wie folgt aus:

SUBSYSTEMS=="usb", DRIVERS=="usb", KERNEL=="sd?1", ACTION=="add", ENV{SYSTEMD_WANTS}+="roboBackup@%k.service"

Nachdem nun alles vorbereitet ist, muss sowohl udev neu gestartet werden, als auch der Dienst roboBackup@.service gestartet werden:

$ sudo /etc/init.d/udev restart
$ sudo systemctl enable roboBackup@.service

Einem ersten Test steht nun nichts mehr im Wege. Zur Sicherheit lediglich die alte log.txt löschen: rm -f ~/log.txt

Also Platte abziehen, Platte einstöpseln, bis 5 zählen, et voilà:

$ cat ~/log.txt
Sat Feb 28 11:09:33 CET 2015
Hello World
sda1

Perfekt! Sowohl udev als auch systemd laufen und arbeiten Hand in Hand!! Bleibt nur noch das Script als solches. Das Gerüst des Backup Scriptes selbst könnte dann wie folgt aussehen:

Dark Theme in Windows 10 aktivieren

Um den noch nicht veröffentlichten „Dark Theme“ in Windows 10 zu aktivieren ist lediglich ein Registry Schlüssel zu setzen:

Und zwar unter:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize

Dort einen neuen DWORD (32-bit) Schlüssel anlegen, diesen „AppsUseLightTheme“ (natürlich ohne Anführungszeichen) nennen und als Wert die 0 zuweisen:

wX_DT

Temperaturfühler DS18B20 per Shell auslesen

Kernemodule laden um den Temperatursensor anzusprechen:

# sudo modprobe w1-gpio
# sudo modprobe w1-therm

Alternativ die Datei /etc/modules mit den Kernelmodulen ergänzen:

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.
 
snd-bcm2835
w1-gpio
w1-therm

Temperatur auslesen und in eine Datenbank pipen:

#!/bin/bash
  
#TempMessung.sh
# Zwei parallel geschaltete Temperaturfühler abfragen und die Werte in eine MySQL Datenbank übertragen
 
SENSOR1=28-00000609c38f
SENSOR2=28-0000060a7b99
TEMP1=$(echo $(cat /sys/bus/w1/devices/$SENSOR1/w1_slave | grep "t=") | cut -d "=" -f2)
TEMP2=$(echo $(cat /sys/bus/w1/devices/$SENSOR2/w1_slave | grep "t=") | cut -d "=" -f2)
 
echo "INSERT INTO schema.table (sensorID, temp) VALUES ('$SENSOR1', $TEMP1);" | mysql -uYourLogin -pYourPassword -h 127.0.0.1;
echo "INSERT INTO schema.table (sensorID, temp) VALUES ('$SENSOR2', $TEMP2);" | mysql -uYourLogin -pYourPassword -h 127.0.0.1;
 
exit 0

Shell Skript über die Datei /etc/crontab automatisiert, minütlich starten:

# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
 
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
* *     * * *   root    /home/pi/TempMessung.sh
#

 

ERGÄNZUNG von 09/2015:

Seit dem Oktoberrelease 2014 von Debian Wheezy muss die Datei /boot/config.txt um folgende Zeile ergänzt werden damit der Pi den Sensor erkennt:

dtoverlay=w1-gpio,gpiopin=4,pullup=on

raspi-config

Nachdem ein frisches Image von Raspdian auf die Karte gebrannt ist und der Pi zum ersten mal gestartet ist, müssen noch einmalig ein paar Einstellungen vorgenommen werden.

Hierfür bietet sich das enthaltene Tool Raspi-Config an, welches in der Shell mit folgendem Kommando zu starten ist:

$ sudo raspi-config

(Der erste Login auf dem Pi gelingt übrigens mit dem Nutzer „pi“ und dem Kennwort raspberry)

  • Als erstes sollte man den nicht genutzen Speicherplatz auf der Karte mit dem Punkt „Expand Filesystem“ verfügbar machen. Nachdem das Script seine Arbeit getan hat, ist ab dem nächsten Neustart der gesammte Platz der Karte verfügbar.
  • Mit Change User Password kann man das Kennwort für den Benutzer „pi“ ändern, und sollte dies auch tun.
  • Für die meisten Fälle kommt beim dem RasPi das Booten zur Konsole in Frage, da er als Desktop Arbeitsplatz zwar grundsätzlich fähig, aber nur bedingt tauglich ist. Hier sollte man also einstellen, dass der Pi nur zur Konsole bootet. Das lässt Resourcen für seinen Job als Webserver, Mailserver, oder oder oder.
  • Bei Internationalisations wird der Pi für den deutschen Sprachraum angepasst:
    •  Change Local auf de_DE.UTF-8 sollte in den meisten Fällen die beste Wahl sein. Unter Umständen kann aber auch de_DE@euro ISO-8856-15 relevant sein. Im Zusammenhang mit älteren Programmen, könnte es hier zwar Probleme geben, ist aber unwahrscheinlich.
    • Unter Change Timezone auf Europe – Berlin umstellen, damit der NTP-Dienst des Pi die korrekte Zeitzone und somit die korrekte Zeit einstellen kann.
    • Change Keyboard Layout: Meistens betreibt man einen Pi ja Headless, sodass man diese Punkt vernachlässigen kann. Aber falls sollte man hier ein deutsches Tastaturlayout auswählen.
  • Advanced Options:
    • Bei Hostname kann man dem Pi einen netteren Namen geben als den Standardnamen „Raspberry“. Nicht das Raspberry schlecht wäre, aber etwas persönlicher darf es ja auch werden 🙂
    • Memorysplit: Für einen Konsolenbetrieb des Pi, kann man hier den für die GPU reservierten Speicher auf ein Minimum von 16MB setzen. Sollte man auch, da man ansonsten den knappen RAM des Pi verschwendet.

Die wichtigsten Einstellungen sollten damit erledigt sein. Aber wer möchte darf natürlich noch ein wenig in den weiteren Optionen des Tools herumstöbern.

Zuletzt sollte man aber nun die neuesten Updates für den Pi herunterladen und installieren. Dies geschieht wieder in der konsole mit den Befehlen:

$ sudo apt-get update
$ sudo apt-get upgrade

Für gewöhnlich ist der Pi damit erstmal ein Weilchen beschäftigt und man hat genügend Zeit für eine Tasse Kaffee, oder auch zwei.

LAMPi – Pi als Webserver

Zunächst kommt als eigentlicher Webserver das bewährte Schwergewicht Apache zum Einsatz. Installiert wird er mit dem Befehl

$ sudo apt-get install apache2

Wenn alles funktioniert hat, kann man zum Testen die IP des Pi auf einem entfernen Rechner als URL eintippen. Hat alles funktioniert, kommt die bekannte „It Works“ Meldung des Apache:

ap2Mit folgendem Befehl wird nun PHP installiert:

$ sudo apt-get install php5

Nach Abschluss der Installation sollte in dem Verzeichnis des Webservers ein kleines PHP Script abgelegt werden um den Erfolg der Installation zu testen:

Also Datei anlegen mit folgendem Befehl:

# sudo nano /var/www/info.php

Folgende Zeilen müssen in den Editor eingegeben werden:

<?php
  phpinfo();
?>

mit Strg+O und Strg+X wird die Datei gespeichert und der Editor beendet.

Anschließend die „neue“ Seite wieder in einem Webbrowser öffnen. Wenn die Ausgabe in etwa wie folgt aussieht, hat es funktioniert:

phpinfoNun fehlt aber noch das M in unserem LAMP-Server (Linux Apache MySQL PHP). MySQL wird daher mit folgendem Befehl installiert:

$ sudo apt-get install mysql-server mysql-client php5-mysql

Nach Abschluss der Installation muss der MySQL-Prozess noch einmal neugestartet werden:

$ sudo /etc/init.d/mysql restart

Damit ist der LAMP dann aktiv und Einsatzbereit. Für ein Testsystem kann es unter Umständen angenehm sein die Datenbank von einem externen Rechner mit der MySQL Workbench zu verwalten. der frisch installierte MySQL Server lauscht aber „leider“ nur auf Anfragen von der IP 127.0.0.1. Das ganze dienst natürlich der Sicherheit. Aber wie gesagt, auf einem Testsystem kann man das ganze lockern. Um dieses Sicherheitsfeature abzuschalten muss in der Datei /etc/mysql/my.cnf die Zeile

bind-address              =127.0.0.1

auskommentiert werden. Anschließend muss der MySQL Dienst noch neu gestartet werden. Wo wir gerade dabei sind die Sicherheit über Bord zu werfen, können wir auch gleich noch den vollen Root Zugriff extern auf den MySQL Dienst zulassen: Hierzu zunächst einmal auf dem Pi mit dem MySQL-Dienst verbinden:

$ mysql -h 127.0.0.1 -u root -pDeinKennwort

In der MySQL Konsole wird nun mit folgenden Befehlen der externe Root Zugriff erlaubt:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'DeinKennwort';
flush privileges;
exit;

Dank des Aufrufs ‚flush privileges“ ist keine Neustart des MySQL-Dienstes hier notwendig. Wer möchte kann nun noch PHP MyAdmin zur Verwaltung der Datenbanken des MySQL Server installieren:

$ sudo apt-get install libapache2-mod-auth-mysql php5-mysql phpmyadmin

Die Frage nach dem installierten Webserver beantworten wir pflichtbewusst mit apache, da wir diesen ja gerade installiert haben. Die zu installierenden Datenbanken lassen wir den Installer ebenfalls einrichten. Soll ja alles laufen hinterher 🙂

Nun muss phpMyAdmin noch mit Apache verknüpft werden. Dazu muss die apache2.conf bearbeitet werden. Also mit folgendem Befehl die Datei in den Texteditor laden:

$ sudo nano /etc/apache2/apache2.conf

Am Ende der Datei muss folgende Zeile eingefügt werden:

Include /etc/phpmyadmin/apache.conf

Mit Strg+O und Strg+X die Datei wieder speichern und den Editor verlassen.

Nachdem der Apache nun mit

$ sudo /etc/init.d/apache2 restart

neu gestartet ist, sollte phpMyAdmin über einen Browser erreichbar sein:

phpmyadminViel Spaß mit dem kleinen Pi WebServer!