Syndicate
Site (RSS, Atom)
Contact
Weblog status
Total entries: 78
Last entry: 2022-10-16 13:52:24
Last updated: 2022-10-16 14:12:58
powered by vim, bash, cat, grep, sed, and nb 3.4.2

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")

Posted by Frank W. Bergmann | Permanent link | File under: shell

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


Posted by Frank W. Bergmann | Permanent link | File under: http, smtp, python

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 

Posted by Frank W. Bergmann | Permanent link | File under: apache

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.


Posted by Frank W. Bergmann | Permanent link | File under: logging, shell

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.


Posted by Frank W. Bergmann | Permanent link | File under: logging, shell, apache

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.


Posted by Frank W. Bergmann | Permanent link | File under: shell

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.


Posted by Frank W. Bergmann | Permanent link | File under: shell, http

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

Posted by Frank W. Bergmann | Permanent link | File under: shell, http, apache

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

Posted by Frank W. Bergmann | Permanent link | File under: ssh, shell

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

Posted by Frank W. Bergmann | Permanent link | File under: shell