Mai 2011 Archives
2011-05-29 12:02:39
Prozessoren, Cores und Hyperthreading
Wie erkennt man auf einem System, wie viele Prozessoren und Cores man hat, und ob Hyperthreading zur Verfügung steht? Fangen wir direkt mit einem Beispiel an:
s1# cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 15 model name : Intel(R) Xeon(R) CPU 5110 @ 1.60GHz stepping : 6 cpu MHz : 1595.984 cache size : 4096 KB physical id : 0 siblings : 2 core id : 0 cpu cores : 2 apicid : 0 initial apicid : 0 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 10 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts pni monitor ds_cpl vmx tm2 ssse3 cx16 xtpr dca lahf_lm bogomips : 3194.84 clflush size : 64 power management: processor : 1 vendor_id : GenuineIntel cpu family : 6 model : 15 model name : Intel(R) Xeon(R) CPU 5110 @ 1.60GHz stepping : 6 cpu MHz : 1595.984 cache size : 4096 KB physical id : 0 siblings : 2 core id : 1 cpu cores : 2 apicid : 1 initial apicid : 1 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 10 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts pni monitor ds_cpl vmx tm2 ssse3 cx16 xtpr dca lahf_lm bogomips : 3192.06 clflush size : 64 power management:
Hier sieht man das "ht"-Flag, aber der Xeon 5110 hat kein Hyperthreading. Zum Vergleich mal ein anderes System:
s2# cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 15 model : 4 model name : Intel(R) Pentium(R) 4 CPU 3.00GHz stepping : 1 cpu MHz : 2995.049 cache size : 1024 KB physical id : 0 siblings : 2 core id : 0 cpu cores : 1 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 5 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe constant_tsc pebs bts sync_rdtsc pni monitor ds_cpl cid xtpr bogomips : 5994.31 clflush size : 64 processor : 1 vendor_id : GenuineIntel cpu family : 15 model : 4 model name : Intel(R) Pentium(R) 4 CPU 3.00GHz stepping : 1 cpu MHz : 2995.049 cache size : 1024 KB physical id : 0 siblings : 2 core id : 0 cpu cores : 1 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 5 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe constant_tsc pebs bts sync_rdtsc pni monitor ds_cpl cid xtpr bogomips : 5990.26 clflush size : 64
Hier steht auch "ht", diesmal hat die CPU aber Hyperthreading. Das Flag wurde wegen einer gewissen Abwärtskompatibilität gesetzt. Grund waren unter anderem Betriebssysteme, die pro Sockel lizenziert wurden. Hätte man das mit dem Pentium4 eingeführte ht-Flag weggelassen, hätten diese "OS" den virtuellen zweiten Kern nicht genutzt / nutzen können.
Wichtig sind hierbei die Angaben zu den Siblings (so etwas wie gleichartige Kinder einer "Vater-CPU"), der Physical ID, der Anzahl der Cores und die Nummerierung der Core IDs. Mit grep wird das dann deutlicher:
s1# egrep \ 'processor|physical id|siblings|core id|cpu cores|^$' \ /proc/cpuinfo processor : 0 physical id : 0 siblings : 2 core id : 0 cpu cores : 2 processor : 1 physical id : 0 siblings : 2 core id : 1 cpu cores : 2
Wir haben 2 CPU cores mit ID 0 und 1 auf 1 physischen Prozessor bei 2 Siblings. die 2 Siblings beziehen sich hier auf die 2 Cores pro physischer CPU.
s2# egrep \ 'processor|physical id|siblings|core id|cpu cores|^$' \ /proc/cpuinfo processor : 0 physical id : 0 siblings : 2 core id : 0 cpu cores : 1 processor : 1 physical id : 0 siblings : 2 core id : 0 cpu cores : 1
Hier haben wir 2 (virtuelle) Prozessoren mit 1 physical ID, 1 Core ID und 1 CPU core, aber mit 2 Siblings. Es handelt sich somit um eine einzelne Singlecore-CPU. Die zwei virtuellen Prozessoren kommen durch die 2 Siblings zustande: Diese CPU hat also Hyperthreading. Pro Core hat man hier also "cpu cores" geteilt durch "siblings" = 2 / 1 = 2 virtuelle HT-Prozessoren.
Schauen wir uns einen dritten Server an:
s3# egrep processor /proc/cpuinfo processor : 0 processor : 1 processor : 2 processor : 3 processor : 4 processor : 5 processor : 6 processor : 7 processor : 8 processor : 9 processor : 10 processor : 11 processor : 12 processor : 13 processor : 14 processor : 15 root@coabmaster:~ > egrep 'core id' /proc/cpuinfo|sort -u core id : 0 core id : 1 core id : 2 core id : 3
Wir haben 16 virtuelle/nicht-virtuelle Prozessoren und 4 Kerne pro physischem Prozessor.
s3# egrep \ 'siblings|cpu cores|physical id' /proc/cpuinfo \ |sort -u cpu cores : 4 physical id : 0 physical id : 1 siblings : 8
Hier sieht man noch mal die Anzahl der Kerne, die IDs der physischen Prozessoren und 8 Siblings (8 Siblings durch 4 Cores = 2 virtuelle HTT-CPUs). Das macht also 2 Quadcore-CPUs mit Hyperthreading = 16 virtuelle Prozessoren.
Mit einem kleinen Script lässt sich das bequem auswerten:
s4# cat cpucores.sh #!/bin/bash for f in \ 'model name' processor 'physical id' 'cpu cores' siblings do grep "$f" /proc/cpuinfo|tail -n 1 done \ |sed 's,.*: ,,' \ |{ read M read P;let P=P+1 read I;[ -z "$I" ] && I=0;let I=I+1 read C;[ -z "$C" ] && C=1 read S;[ -z "$S" ] && S=1 echo $M: $I CPUs with $C cores and $S siblings\ $([ $S -gt $C ] && echo " (hyperthreading)") \ '("'$P virtual processors'")' } s4# ./cpucores.sh Intel(R) Xeon(R) CPU E5520 @ 2.27GHz: 2 CPUs with 4 cores and 8 siblings (hyperthreading) ("16 virtual processors")
Da das Script so kurz ist, kann man es auch als Einzeiler verwenden. Zum Schluss noch ein paar Beispielausgaben des Scripts:
Intel(R) Xeon(R) CPU E5520 @ 2.27GHz: 2 CPUs with 4 cores and 8 siblings (hyperthreading) ("16 virtual processors") Intel(R) Xeon(R) CPU X5650 @ 2.67GHz: 2 CPUs with 6 cores and 12 siblings (hyperthreading) ("24 virtual processors") Intel(R) Pentium(R) 4 CPU 3.00GHz: 1 CPUs with 1 cores and 2 siblings (hyperthreading) ("2 virtual processors") Intel(R) Core(TM)2 CPU 4400 @ 2.00GHz: 1 CPUs with 2 cores and 2 siblings ("2 virtual processors") Intel(R) Xeon(R) CPU 3060 @ 2.40GHz: 1 CPUs with 2 cores and 2 siblings ("2 virtual processors") Intel(R) Xeon(R) CPU 5110 @ 1.60GHz: 4 CPUs with 2 cores and 2 siblings ("4 virtual processors") Intel(R) Xeon(R) CPU E5310 @ 1.60GHz: 1 CPUs with 4 cores and 4 siblings ("4 virtual processors") Intel(R) Xeon(R) CPU E5520 @ 2.27GHz: 2 CPUs with 4 cores and 8 siblings (hyperthreading) ("8 virtual processors") Intel(R) Xeon(R) CPU E5620 @ 2.40GHz: 2 CPUs with 4 cores and 8 siblings (hyperthreading) ("8 virtual processors")
2011-05-26 23:15:58
base64 für SMTP-Auth und HTTP Basic authentication
Sowohl bei SMTP-Auth als auch bei HTTP Basic access authentication kommt base64-Kodierung zur Anwendung. Dieser Blogpost zeigt dazu Beispiele und die Verwendung von Python zur base64-Kodierung.
SMTP-Auth
Hier der Ausschnitt eines SMTP-Dialogs mit PLAIN-Authentication:
$ telnet mail.domain.de 25 Trying 128.64.32.16... Connected to mail.domain.de. Escape character is '^]'. 220 mail.domain.de ESMTP Postfix EHLO franksbox.localdomain 250-mail.domain.de 250-PIPELINING 250-SIZE 35840000 250-ETRN 250-AUTH LOGIN PLAIN 250-AUTH=LOGIN PLAIN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN AUTH PLAIN bWFpbDEAbWFpbDEAc2FzbHB3 235 2.0.0 Authentication successful
Nach RFC4616 besteht die Zeichenkette für den "PLAIN SASL Mechanism" aus der "authorization identity", einem NUL-Zeichen, der "authentication identity", einem weiteren NUL-Zeichen und dem Passwort. Normalerweise sind "authorization identity" und "authentication identity" gleich (die Postfachkennung). Mit Python kann man die Zeichenkette mit base64 kodieren und auch zurück dekodieren:
$ python -c "import base64;print \ > base64.encodestring('mail1\0mail1\0saslpw')" bWFpbDEAbWFpbDEAc2FzbHB3 $ python -c "import base64;print \ > base64.decodestring('bWFpbDEAbWFpbDEAc2FzbHB3')" \ > |tr \\000 / mail1/mail1/saslpw
HTTP basic access authentication
Auch hier kommt base64-Kodierung zum Einsatz. Die Zeichenkette zur Authorisierung besteht nach RFC1945 aus Name, einem Doppelpunkt und dem Passwort. Ein HTTP-Request sieht damit beispielsweise so aus:
GET /index.html HTTP/1.1 Host: www.domain.de Authorization: Basic dzE6aHRwdw==
Auch hier nutzen wir wieder Python, um manuell zu en- und dekodieren.
$ python -c \ > "import base64;print base64.encodestring('w1:htpw')" dzE6aHRwdw== $ python -c \ > "import base64;print base64.decodestring('dzE6aHRwdw==')" w1:htpw
2011-05-25 00:35:23
Apache hat keine freie Semaphore
Das ist auch ein kleiner Klassiker, darum sollen dieses Problem und seine Lösung auch nicht unerwähnt bleiben. Es kann vorkommen, dass in einem Apache Error-Log die folgende Zeile auftaucht:
No space left on device (errno: 28)
Eine Prüfung ergibt dann oft, dass auf den (HD-) Devices sehr wohl noch "Space" vorhanden ist. In den Logzeilen findet sich dann auch ein Eintrag wie:
could not create private SSLMutex semaphore
Das liefert dann auch den entscheidenden Hinweis darauf, dass Apache keinen neuen Semaphor (ein klassisches Werkzeug für IPC) erzeugen kann. Die man-page zu semget() führt auch diese Fehlermöglichkeit auf:
# man semget|grep -A4 ENOSPC ENOSPC A semaphore set has to be created but the system limit for the maximum number of sema- phore sets (SEMMNI), or the system wide max- imum number of semaphores (SEMMNS), would be exceeded.
Das sind bei vielen Hosts oft noch die zu niedrigen Standardwerte:
# cat /proc/sys/kernel/sem 250 32000 32 128
Die man-page proc(5) liefert uns folgende Infos dazu:
/proc/sys/kernel/sem (since Linux 2.4) This file contains 4 numbers defining limits for System V IPC semaphores. These fields are, in order: SEMMSL The maximum semaphores per semaphore set. SEMMNS A system-wide limit on the number of semaphores in all semaphore sets. SEMOPM The maximum number of operations that may be specified in a semop(2) call. SEMMNI A system-wide limit on the maximum num- ber of semaphore identifiers.
Eine Zählung der Semaphore des Users "www" liefert das:
# ipcs -s|grep -c www 128
Jetzt stoppen wir Apache, löschen alle "vergessenen" Semaphore, setzen die Werte höher und starten Apache wieder:
# ipcs -s|grep www|cut -d\ -f2|xargs -r -n 1 ipcrm -s # echo '500 64000 32 1024' >/proc/sys/kernel/sem
2011-05-21 09:37:23
Logging in der Konsole
Dieser Post zeigt ein paar Möglichkeiten, wie man Befehle oder Ausgaben in einer Shell-Session mitschneiden kann.
Der Befehl script erzeugt eine neue Shell, bei der alle Ein- und Ausgaben in eine Datei typescript geschrieben werden. Nach Verlassen der durch script gestarteten Shell kann man sich dieses Logfile anschauen. Allerdings ist dort jedes einzelne Zeichen aufgezeichnet, einschliesslich aller Steuerzeichen für Farben, für Zeilen Editierung (Backspace, Tab, Return etc). Wie man mittels vi dieses Log von Steuerzeichen befreit, würde diesen Beitrag sprengen.
Als Alternative kann man sich auch nur die Textausgabe von Programmen in ein Logfile packen. Hier ein Beispiel:
$ avscan -a . 2>&1 |tee -a log.avscan
Wenn man ein Logging mit Timestamp der einzelnen Zeilen braucht, kann man so etwas machen:
$ /opt/drweb/drweb -al . 2>&1 |tai64n |tee -a log.drweb @400000004c5bbe8b1d775b9c Dr.Web (R) Scanner for Linux @400000004c5bbe8b1e3010c4 Copyright (c) Igor Daniloff,
Das Tool tai64n gehört zu der Softwaresuite daemontools von Dan Bernstein. Hier fügt tai64n am Beginn jeder Zeile einen Timestamp @40000... ein. Lesen/konvertieren kann man das mit tai64nlocal, was den tai64n-Timestamp in lokale und human readable Zeit konvertiert:
$ tai64nlocal <log.drweb |tail -1 2010-08-06 09:43:03.225062500 2009_02_12-ftp.log.gz - Ok $
Man kann sich den "Live-Stream" auch direkt bei der Ausgabe wieder konvertiert anzeigen lassen:
$ /opt/drweb/drweb -al . 2>&1 |tai64n \ |tee -a log.drweb |tai64nlocal 2010-08-06 09:47:52.433362500 Dr.Web (R) Scanner for Linux 2010-08-06 09:47:52.433364500 Copyright (c) Igor Daniloff,
Wenn man mit sehr viel Daten bei der Ausgabe rechnet und vielleicht nur den letzten Teil haben möchte, dann kann man so eine Zeile nutzen:
$ /opt/drweb/drweb -al . 2>&1 |tee /dev/stderr \ |multilog t s10000 n20 ./logdir
Diese Zeile zeigt die Programmausgabe kontinuierlich an und schreibt bis 20 maximal 10 KB große Logdateien in das Verzeichnis logdir. Das Tool multilog aus den daemontools hat ein eingebautes "logrotate". Auf diese Weise kann man die Menge der Logdaten begrenzen.
2011-05-20 08:00:18
access_log-Statistiken mit awk
Heute gibt's nur kleine Einzeiler. Ein Klassiker zum Anzeigen der IP-Adressen eines Apache access_log, letzte 1000 Zugriffe und sortiert nach Häufigkeit der Zugriffe:
tail -n 1000 access_log | awk \ '{f[$1]++}END{for(g in f)print f[g]" "g}' \ | sort -n | tail -n 5
Möchte man nach der angefragten Datei sortieren, muss man '$1' durch '$7' ersetzen, für Sortierung nach Return Code '$9'.
tail -n 1000 access_log | awk \ '$9=="404"{f[$7" "$11]++}END{for(g in f)print f[g]" "g}' \ | sort -n | tail -n 5
Das sortiert die Zeilen mit 404 Return Code ("File Not Found") und gibt dabei die angeforderte Datei und den Referer an.
tail -n 1000 access_log | awk \ '$9~/30./{f[$7" "$11]++}END{for(g in f)print f[g]" "g}' \ | sort -n | tail -n 5
Statt 404 werden hier alle 30x Redirects sortiert.
2011-05-19 17:44:08
Interaktionen mit expect
Auch wenn die "großen" Zeiten von Tcl/Tk ("Tickel-Tikay") vorbei sind, es gibt immer noch einige Leute, die die Scriptscprache und das Toolkit nutzen. Es ist stabil und gut dokumentiert. Ein aus dem Tcl-Umfeld entstandenes Programm ist expect, mit dem man Interaktionen bzw. Dialoge mit anderen Programmen oder auch Serverdiensten realisieren kann.
Die man-page zu expect erklärt die Grundlagen. Hier ist ein Beispiel für die Verwendung von expect aus einem bash-Script heraus:
> cat check_easyraid.sh #!/bin/bash CMD=$1 [ "$CMD" ] || { echo "usage: echo PASSWD | $0 easyraidcommand ip-address" exit 1 } IP=$2 [ "$IP" ] || exit 2 ulimit -t 4 read -t 1 PASS cat <Das Script baut eine telnet-Session zu einem easyRAID-SAN auf und schickt Befehle zum Testen ab. Man kann mit expect auch ftp-Sessions oder andere Interaktionen aus Scripts heraus einfach handhaben. Das Beispiel ist ein Mix aus bash und expect, aber man kann mit dem passenden Shebang natürlich auch "reine" expect-Scripts schreiben.
2011-05-18 17:17:28
Lynx Kurzanleitung
Ein paar Kommandozeilenoptionen:
lynx -auth=USER:PW http://xxx.localdomain:8080/ lynx -source -mime-header http://www.meinedomain|head -12 lynx -dump http://www.meinedomain/|head lynx http://www.foo.bar
Der erste Befehl bekommt als Option noch ein Account/PW-Tupel für HTTP-AUTH übergeben. In diesem Fall versucht lynx aber trotzdem als erstes den Abruf ohne HTTP-AUTH, gibt dann evtl. eine Meldung aus, dass Authorisierung verlangt wird, und versucht es dann mit den angegebenen Daten.
Der zweite Befehl gibt den Quelltext (natürlich meist HTML) und den MIME/HTTP-Header aus. Dieser Befehl ist oft ganz nützlich zur Fehlersuche, um beispielsweise Redirects, SSL-Verbindungen, Cache-Einstellungen oder mehr zu überprüfen.
Der dritte Befehl gibt den interpretierten Quelltext aus. "Interpretiert" bedeutet hier, bezogen auf eine Shell mit Textausgabe und vermutlich HTML als Eingabe, dass sozusagen eine Wandlung HTML => Text stattfindet.
Der vierte Befehl startet eine interaktive Browser-Session. Bedienung in interaktiver Session (nur ein paar von vielen Tasten):
- Navigieren hoch/runter mit Pfeiltasten Up/Down
- Navigieren in Browserhistory mit Pfeiltasten Left/Right
- Seitenweise hoch/runter mit Ctrl-B/Ctrl-F
- Suchen wie auch bei ''more'', ''less'' oder ''man'' mit "/"
- letzte Suche wiederholen mit "n"
- Reload mit Ctrl-R
- URL editieren mit "G"
- Verlassen mit "Q"
Will man einen Header mit "Expires" prüfen (z.B. bei einem Apache mit mod_expires), dann läßt sich das mit Lynx einfach durchführen:
> date Mo 27. Sep 13:52:01 CEST 2010 > lynx -source -mime-header http://www.tuxad.de \ |sed -n '0,/^^M$/p' HTTP/1.0 200 OK Server: fnord/1.11 Content-Type: text/html Expires: Mon, 27 Sep 2010 15:52:50 GMT Content-Length: 10225 Last-Modified: Sat, 10 Oct 2009 11:38:27 GMT
(Anm.: Das "^M" steht für Eingabe von "Ctrl-V Ctrl-M".)
Die eigene IP-Adresse kann man mit diversen Diensten im Netz herausfinden. Bei einem grafischen Browser mag man bei diesen mit Werbung überfrachteten "Diensten" ja noch einigermassen schnell die IP-Adresse sehen, aber mit lynx sieht das so aus:> lynx -dump ....de szmtag [1][?] Navigation: (35 Zeilen gelöscht) [40]Computerbild Ihre IP-Adresse ist : 83.246.xxx.xxx (182 Zeilen gelöscht)Ohne die gelöschten Zeilen würde man die IP-Adresse kaum auf Anhieb sehen können. Und das Herausfiltern der IP-Adresse zur Weiterverwendung in Scripts ist auch nicht ganz einfach. Ein für Lynx und darauf basierenden Scripts gut geeigneter Dienst bietet tdyn.de:
> lynx -dump showip.tdyn.de/showip 83.246.xxx.xxx
Alternativ kann man auch das kleine Tool "showip" aus den sac-tools verwenden (ca. 1,5 KB static binary i386). Weitere Online-Tools stehen unter http://www.tuxad.de/online-tools-short-url-traceroute-showip.html beschrieben.
2011-05-17 21:25:01
Apache und MySQL supervised
Unter notfall-sshd_oom-resistent steht beschrieben, wie man sshd supervised (mit den daemontools von DJB) betreibt. Dieser Post zeigt Beispiele, wie auch Apache und MySQL unter der Kontrolle von supervise laufen.
Apache
> ps axuwf|... /command/svscan /service/ \_ supervise apache-sv \_ /usr/sbin/apache2 -f /etc/httpd/httpd.conf -D FOREG.. > cat /service/apache-sv/run #!/bin/bash exec 2>&1 # don't respawn too fast sleep 1 # in case that apache lost his father "supervise" kill the # procs ps axuwf |grep -v grep \ |grep ' /usr/sbin/apache2 ' \ |awk '{print$2}' \ |xargs -r kill -TERM exec /usr/sbin/apache2 -f /etc/httpd/httpd.conf -D FOREGROUND
MySQL
#!/bin/bash export PATH=/command:$PATH:/usr/local/bin:/usr/local/sbin PROC_PATTERN=usr.sbin.mysqld MAX_KILL_ATTEMPTS=20 SCRIPT=$(pwd)/$0 get_pid() { PID=$(/bin/ps axwf \ |grep $PROC_PATTERN|grep -v grep\ |awk '{print$1}' 2>/dev/null) } kill_procs() { COUNT=0 get_pid while [ "$PID" ] do kill -TERM $PID 2>/dev/null let COUNT=COUNT+1 [ "$COUNT" -gt $MAX_KILL_ATTEMPTS ] \ && kill -9 $PID 2>/dev/null sleep 3 get_pid done } # we must be sure: kill all remaining procs kill_procs # this should never be reached, otherwise there are # maybe too many databases/tables on this host ulimit -n 250000 exec /usr/sbin/mysqld \ --defaults-file=/etc/mysql/my.cnf \ --basedir=/usr \ --datadir=/var/lib/mysql \ --pid-file=/var/run/mysqld/mysqld.pid \ --socket=/var/run/mysqld/mysqld.sock
2011-05-17 18:17:24
Notfall-sshd OOM-resistent
Dieser Artikel beschreibt, wie man einen SSH-Dienst mit maximaler Zuverlässigkeit betreibt. In extremen Notfällen, wenn beispielsweise ein "normal" gestarteter sshd durch einen OOM-Kill (Out Of Memory) des Kernels beendet wurde, wünscht sich ein Admin gerne noch eine Login-Möglichkeit.
Hier zeigt sich der große Nachteil eines "normal" gestarteten Daemons (per SysV-Script oder vergleichbar), bei dem vielleicht noch ein PID-File geschrieben wird, es aber keine Instanz gibt, die über ein Ende des Daemons unmittelbar informiert wird. Tools wie monit verschlimmbessern die Lage, da es einen weiteren Prozess gibt, der aber trotzdem das Ende eines Daemons nicht direkt mitbekommt, sondern prüfen muß, ob der Daemon noch läuft.
ssh mit supervising
Einen einfachen Ausweg bietet die supervising-Methode, bei der ein Supervise-Prozess unmittelbar und sofort vom Ende eines als Kind laufenden Daemons vom Kernel informiert wird und diesen neu starten kann.
Die daemontools von DJB bieten Supervising von Prozessen. So sieht beispielhaft eine Prozesshierarchie mit einem supervised sshd aus:
/command/svscan /service/ \_ supervise sshd-sv \_ /usr/sbin/sshd -D -p 8234 -o PidFile=/var/run/sshd.pid
Das von supervise gestartete Script sieht so aus:
#!/bin/sh exec 2>&1 # don't respawn too fast /bin/sleep 1 exec /usr/sbin/sshd -D -p 8234 -o PidFile=/var/run/sshd.pid \ -o UseDNS=no
Da die supervise-Hierarchie über init mit Option "respawn" gestartet wird, ist somit auch der Restart von supervise selbst gesichert (beispielsweise bei den oben erwähnten Out-Of-Memory-Kills des Kernels). Bei SysV-init kann die Konfigurationszeile unmittelbar nach "si" (system init) eingetragen werden, so dass man sich bereits einloggen kann, während die Bootscripts noch gestartet werden. So sehen beispielhaft Konfigurationen für SysV-Init und Upstart aus:
# grep -B1 SV /etc/inittab si::sysinit:/sbin/rc sysinit SV:2345:respawn:/command/svscanboot3 # cat /etc/init/daemontools.conf description "DJB daemontools" start on filesystem stop on runlevel [06] respawn exec /command/svscanboot3 #
ssh mit supervising und ramfs
So zuverlässig sshd über supervise über svscan über ... init läuft, wenn das root-FS in Notfällen vom Kernel (oder von root per Magic Sysrq) RO-remountet wird, kann supervise keinen sshd mehr starten, da Schreibzugriff benötigt wird. Als einfacher Ausweg aus der Misere bietet sich hier ramfs an. Wenn supervise das run-Script gestartet hat, kann aber innerhalb des Scripts nicht einfach das ramfs gemountet werden, da dann mit svc über die control-Pipe nicht mehr supervise kontrolliert werden kann. Daher wird in dem folgenden run-Script nicht svc genutzt, sondern supervise direkt über ein echo in die control-Pipe beendet, damit ein "neues" supervise von svscan gestartet werden kann, das dann das ramfs im supervise-Verzeichnis nutzt.
#!/bin/sh exec 2>&1 # don't respawn too fast /bin/sleep 1 # if supervise is not a ramdisk try to mount it as ramdisk grep -q sshd-sv.supervise /proc/mounts || { /bin/rm -rf supervise-nativefs mv supervise supervise-nativefs && { if mkdir -p supervise then if mount -t ramfs /dev/ram0 supervise then echo -e 'dx\c' >supervise-nativefs/control else rmdir supervise mv supervise-nativefs supervise fi else mv supervise-nativefs supervise fi } } exec /usr/sbin/sshd -D -p 8234 \ -o PidFile=/var/run/sshd-sv.pid \ -o UseDNS=no
2011-05-11 21:54:16
BASH Dateideskriptoren / file descriptors
Standardfehler-Ausgabe generell auf STDOUT umlenken mittels "exec 2>&1":
$ ( echo ERROR >&2; ) |grep NIX ERROR $ ( exec 2>&1; echo ERROR >&2; ) |grep NIX $
Generell STDIN umleiten bzw. schließen:
> echo TEST | ( cat -; ) TEST > echo TEST | ( exec </dev/null; cat -; ) bash: echo: write error: Datenübergabe unterbrochen (broken pipe) > echo TEST | ( exec <&-; cat -; ) bash: echo: write error: Datenübergabe unterbrochen (broken pipe) cat: -: Ungültiger Dateideskriptor cat: schließe Standardeingabe: Ungültiger Dateideskriptor >
Zusätzlichen Filedeskriptor öffnen, STDOUT (zwecks Weiterverarbeitung) duplizieren und am Ende wieder schließen:
> exec 3<&1 > echo 123|tee /proc/self/fd/3 123 123 > exec 3<&- > echo 123|tee /proc/self/fd/3 tee: /proc/self/fd/3: Datei oder Verzeichnis nicht gefunden 123