<?xml version="1.0" encoding="iso-8859-1"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
<?xml-stylesheet type="text/css" href="http://localhost/please/edit/me/styles/feed.css"?>
<title type="html">tuxad blog</title>
<subtitle type="html">news and more</subtitle>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me" />
<link rel="self" type="application/atom+xml" href="http://localhost/please/edit/me/atom.xml" />
<updated>2011-12-31T21:54:15+01:00</updated>
<author>
<name>Frank W. Bergmann</name>
<uri>http://localhost/please/edit/me</uri>
</author>
<id>http://localhost/please/edit/me/</id>
<generator uri="http://nanoblogger.sourceforge.net" version="3.4.2">NanoBlogger</generator>
<entry>
<title type="html">DJB daemontools with upstart or systemd</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/12/31/djb_daemontools_with_upstart_or_systemd/index.html" />
<id>http://localhost/please/edit/me/archives/2011/12/31/djb_daemontools_with_upstart_or_systemd/index.html</id>
<published>2011-12-31T18:37:32+01:00</published>
<updated>2011-12-31T18:37:32+01:00</updated>
<category term="shell" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>The daemontools softwaresuite are widely used for supervising processes. Unlike the common way of launching daemons or other processes in background, writing their PID to a file and watch for a process (actually 
<em>any</em>process) with this PID by crappy tools like monit the daemontools offer a direct supervision of processes with an immediate restart on a crash.</p>
<p>Using the traditional 
<strong>SysV-init</strong>it is most easy to launch the daemontools processes:</p>
<pre>
$ grep -B1 SV /etc/inittab
si::sysinit:/etc/rc.d/rc.sysinit
SV:12345:respawn:/command/svscanboot3
</pre>
<p>
<em>Note: svscanboot3 is a binary replacement of svscanboot. It is part of 
<a href="http://www.tuxad.com/download-ngtx.html">ngtx</a>.</em>
</p>
<p>SysV-init process ID 1 is very small, approx. 700 KB RSS. With many manual optimizations it is possible to start a system / server as fast as with upstart or systemd.</p>
<p>
<strong>Upstart</strong>offers event-based booting. A time ago it was dealed as a successor to SysV-init. To start daemontools as a upstart-service you must create a config file:</p>
<pre>
$ cat /etc/init/daemontools.conf 
description     "DJB daemontools"
start on filesystem
stop on runlevel [06]
respawn
exec /command/svscanboot3
</pre>
<p>Some latest Linux (actual "linux-only") distros switch to 
<strong>systemd</strong>. Systemd also offers event-based and parallel booting with linux-only features like cgroups or fanotify. Its features are very nice but its PID 1 RSS is 13 MB which is very big compared to SysV-init. For systemd you must also create a config file (and a symlink):</p>
<pre>
$ ls -l /etc/systemd/system/multi-user.target.wants/ \
  daemontools.service
lrwxrwxrwx. 1 root root 39 21. Dez 08:34
  /etc/systemd/system/multi-user.target.wants/ \
  daemontools.service -&gt; /lib/systemd/system/ \
  daemontools.service

$ ls -l /lib/systemd/system/daemontools.service
-rw-r--r--. 1 root root 151 21. Dez 08:33
  /lib/systemd/system/daemontools.service

$ cat /lib/systemd/system/daemontools.service
[Unit]
Description=DJB daemontools
After=sysinit.target

[Service]
ExecStart=/command/svscanboot3
Restart=always

[Install]
WantedBy=multi-user.target
</pre>
</div>
</content>
</entry>
<entry>
<title type="html">MySQL Slow Query Log Filter</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/12/03/mysql_slow_query_log_filter/index.html" />
<id>http://localhost/please/edit/me/archives/2011/12/03/mysql_slow_query_log_filter/index.html</id>
<published>2011-12-03T20:53:11+01:00</published>
<updated>2011-12-03T20:53:11+01:00</updated>
<category term="mysql" />
<category term="shell" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Filtering all queries of 
<em>one</em>user out of a MySQL Slow Query Log is a common task. Maatkit is a toolkit for analyzing log files and more. Here is an example run to filter all queries of user123 of a 707 MB big slow-query-log:</p>
<pre>
$ time mk-query-digest --filter \
 '($event-&gt;{user} || "") =~ m/user123/' \
 --print --no-report log-slow-queries.log &gt;1
log-slow-queries.log:  15% 02:49 remain
log-slow-queries.log:  29% 02:26 remain
log-slow-queries.log:  44% 01:51 remain
log-slow-queries.log:  59% 01:20 remain
log-slow-queries.log:  76% 00:45 remain
log-slow-queries.log:  90% 00:18 remain

real    3m20.097s
user    0m16.616s
sys     3m2.592s
</pre>
<p>Well, 707 MB in more than 3 minutes? Simple filtering can also be done with awk, try it:</p>
<pre>
$ time awk \
'/^# Time: /{t=1;s=$0;p=0}'\
'!/^# /{t=0}/^# User@Host: /{p=0}'\
'/^# User@Host: user123/{p=1};'\
'{if(p){if(t){print s;t=0;}print$0}}' \
 &lt;log-slow-queries.log &gt;2

real    0m58.844s
user    0m2.501s
sys     0m3.268s
</pre>
<p>Nice speed, but awk is a symlink to mawk, try gawk:</p>
<pre>
$ time gawk \
'/^# Time: /{t=1;s=$0;p=0}'\
'!/^# /{t=0}/^# User@Host: /{p=0}'\
'/^# User@Host: user123/{p=1};'\
'{if(p){if(t){print s;t=0;}print$0}}' \
 &lt;log-slow-queries.log &gt;2

real    3m30.287s
user    0m29.934s
sys     2m58.800s
</pre>
<p>Ooops, but didn't we already know, how 
<a href="http://www.tuxad.de/blog/archives/2010/09/17/gnu_grep_speed_comparison_fixed_strings/index.html">slow</a>GNU-software can be? Try a different server:</p>
<pre>
$ time gawk \
'/^# Time: /{t=1;s=$0;p=0}'\
'!/^# /{t=0}/^# User@Host: /{p=0}'\
'/^# User@Host: user123/{p=1};'\
'{if(p){if(t){print s;t=0;}print$0}}' \
 &lt;log-slow-queries.log &gt;2

real    2m4.899s
user    2m2.240s
sys     0m1.890s
</pre>
<p>This server runs more fast, but it lacks mawk, is virtual and it runs like the first server only 32-bit-linux. Try gawk and mawk on 64-bit-linux (same physical host):</p>
<pre>
$ time gawk \
'/^# Time: /{t=1;s=$0;p=0}'\
'!/^# /{t=0}/^# User@Host: /{p=0}'\
'/^# User@Host: user123/{p=1};'\
'{if(p){if(t){print s;t=0;}print$0}}' \
 &lt;log-slow-queries.log &gt;2

real    1m49.348s
user    1m40.242s
sys     0m1.528s

$ time mawk \
'/^# Time: /{t=1;s=$0;p=0}'\
'!/^# /{t=0}/^# User@Host: /{p=0}'\
'/^# User@Host: user123/{p=1};'\
'{if(p){if(t){print s;t=0;}print$0}}' \
 &lt;log-slow-queries.log &gt;3

real    0m13.115s
user    0m1.000s
sys     0m2.392s
</pre>
<p>Conclusions: 
<ul>
<li>simple filter can be done faster with awk than with maatkit</li>
<li>mawk does this filtering faster than gawk</li>
<li>mawk and gawk run faster on 64-bit-linux</li>
</ul></p>
</div>
</content>
</entry>
<entry>
<title type="html">Indirekte Variablenzuweisung mit &quot;eval&quot;</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/11/30/indirekte_variablenzuweisung_mit_eval/index.html" />
<id>http://localhost/please/edit/me/archives/2011/11/30/indirekte_variablenzuweisung_mit_eval/index.html</id>
<published>2011-11-30T22:15:57+01:00</published>
<updated>2011-11-30T22:15:57+01:00</updated>
<category term="shell" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Das Shell-Builtin "eval" bewertet Ausdr&uuml;cke bzw. f&uuml;hrt Befehle aus. Einfaches Beispiel:</p>
<pre>
$ unset A
$ echo $A

$ eval A=1
$ echo $A
1
</pre>
<p>Da die Shell vor Ausf&uuml;hren von eval wie auch bei jeder anderen Kommandozeile erst die &uuml;blichen Ersetzungen (Variablen, Commands etc.) macht, kann man auch folgendes machen:</p>
<pre>
$ B=A
$ eval $B=2
$ echo $A
2
</pre>
<p>Und wenn man ganz verr&uuml;ckte Sachen machen will, wie beispielsweise in einem Script mehrere Variablen in einer Schleife auf die gleiche Weise zu ver&auml;ndern, dann sieht das so aus:</p>
<pre>
$ U=a
$ for i in U;do eval $i=\"\$$i X\";done;echo $U
a X
$ for i in U;do eval $i=\"\$$i X\";done;echo $U
a X X
$ for i in U;do eval $i=\"\$$i X\";done;echo $U
a X X X
</pre>
</div>
</content>
</entry>
<entry>
<title type="html">Call to undefined function gzopen()</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/09/19/call_to_undefined_function_gzopen/index.html" />
<id>http://localhost/please/edit/me/archives/2011/09/19/call_to_undefined_function_gzopen/index.html</id>
<published>2011-09-19T22:07:58+01:00</published>
<updated>2011-09-19T22:07:58+01:00</updated>
<category term="c" />
<category term="php" />
<category term="developer" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Auf 32-Bit-Systemen und aktiviertem Largefilesupport in der Zlib kann es beispielsweise bei Verwendung von PHP zu "Fehlern" kommen. Dieser Fehler erschien bei dem Versuch, Magento auf einem 32-Bit-System mit LFS-Support in Zlib und PHP zu installieren:</p>
<pre>
Fatal error: Call to undefined function gzopen() in \
  /html/install/downloader/lib/Mage/Archive/Gz.php on line 60
</pre>
<p>Das ist aber anscheinend ein allgemeines Problem und durchaus aktuell, wie dieser Thread zeigt: 
<a href="https://bugs.launchpad.net/ubuntu/+source/php5/+bug/432291">https://bugs.launchpad.net/ubuntu/+source/php5/+bug/432291</a></p>
<p>Der Fehler tauchte bei dieser Distro auf, nachdem der Debian-Patch "019-z_off_t_as_long.patch" deaktiviert wurde. Dabei trat dann der Nebeneffekt auf, dass nur noch gzopen64() definiert war. Der Ansatz war ja l&ouml;blich, den Patch nicht ungepr&uuml;ft von dieser Distribution zu &uuml;bernehmen (ya remember "OpenSSL-Debakel" und "16 Bit Entropie"?), doch leider wurde dieser Patch dann doch wieder aktiviert, anscheinend ohne sich &uuml;ber die Hintergr&uuml;nde im Klaren zu sein. Zu dem Patch findet man folgende Infos:</p>
<pre>
* Add 019-z_off_t_as_long.patch, including local headers for
zlib, forcing off_t = long for gzip file functions, however
disable it for now, as we'll only need it if we reenable LFS
(closes: #208608)
</pre>
<p>Der Patch bewirkt die Installation von zwei Zlib-Header-Dateien. Dabei wird der Zlib-interne off_t-Typ als "long" definiert. Die Header-Dateien selbst stammen von der Zlib 1.2.1.1 und &uuml;berschreiben ihre Br&uuml;der, die systemweit installiert sind und vermutlich von einer neueren Zlib stammen. So eine Vorgehensweise "unsauber" zu nennen, w&auml;re ein Kompliment, aber zum Thema QM kann nur noch einmal auf OpenSSL und die 16 Bit breite Entropie verwiesen werden.</p>
<p>Doch wie l&ouml;st man das Problem? Als Maintainer kann man bugs.php.net bem&uuml;hen oder es &uuml;ber einen Kontakt kl&auml;ren. F&uuml;r die Homebrew-Variante schauen wir uns mal einen Teil der 
<b>aktuellen</b>Zlib-Header-Dateien an:</p>
<pre>
$ grep -B1 -A21 "define gzopen" /usr/include/zlib.h 
#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && \
_LFS64_LARGEFILE-0
#  define gzopen gzopen64
#  define gzseek gzseek64
#  define gztell gztell64
#  define gzoffset gzoffset64
#  define adler32_combine adler32_combine64
#  define crc32_combine crc32_combine64
#  ifdef _LARGEFILE64_SOURCE
     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const \
char *));
     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, \
int));
     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong,
\
z_off_t));
     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, \
z_off_t));
#  endif
#else
   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char \
*));
   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, \
z_off_t));
   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, \
z_off_t));
#endif
</pre>
<p>Da wir die Zlib intern in PHP nutzen wollen und dabei auf keinen Fall gzopen64(), sondern statt dessen gzopen() haben wollen, definieren wir zum &Uuml;bersetzen von PHP ganz einfach ZLIB_INTERNAL, beispielsweise mit der gcc-Option "-DZLIB_INTERNAL=1". Wenn man das an die CFLAGS anh&auml;ngt, bevor man ./configure aufruft, dann wird PHP damit &uuml;bersetzt und beim Include der Zlib-Header-Dateien werden die "internen" Namen gzopen() etc. deklariert.</p>
</div>
</content>
</entry>
<entry>
<title type="html">Prozessoren, Cores und Hyperthreading</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/05/29/prozessoren_cores_und_hyperthreading/index.html" />
<id>http://localhost/please/edit/me/archives/2011/05/29/prozessoren_cores_und_hyperthreading/index.html</id>
<published>2011-05-29T12:02:39+01:00</published>
<updated>2011-05-29T12:02:39+01:00</updated>
<category term="shell" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Wie erkennt man auf einem System, wie viele Prozessoren und Cores man hat, und ob Hyperthreading zur Verf&uuml;gung steht? Fangen wir direkt mit einem Beispiel an:</p>
<pre>
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:
</pre>
<p>Hier sieht man das "ht"-Flag, aber der Xeon 5110 hat 
<em>kein</em>Hyperthreading. Zum Vergleich mal ein anderes System:</p>
<pre>
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
</pre>
<p>Hier steht auch "ht", diesmal hat die CPU aber Hyperthreading. Das Flag wurde wegen einer gewissen Abw&auml;rtskompatibilit&auml;t gesetzt. Grund waren unter anderem Betriebssysteme, die pro Sockel lizenziert wurden. H&auml;tte man das mit dem Pentium4 eingef&uuml;hrte ht-Flag weggelassen, h&auml;tten diese "OS" den virtuellen zweiten Kern nicht genutzt / nutzen k&ouml;nnen.</p>
<p>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:</p>
<pre>
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
</pre>
<p>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.</p>
<pre>
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
</pre>
<p>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.</p>
<p>Schauen wir uns einen dritten Server an:</p>
<pre>
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:~ &gt; egrep 'core id' /proc/cpuinfo|sort -u
core id         : 0
core id         : 1
core id         : 2
core id         : 3
</pre>
<p>Wir haben 16 virtuelle/nicht-virtuelle Prozessoren und 4 Kerne pro physischem Prozessor.</p>
<pre>
s3# egrep \
'siblings|cpu cores|physical id' /proc/cpuinfo \
|sort -u
cpu cores       : 4
physical id     : 0
physical id     : 1
siblings        : 8
</pre>
<p>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.</p>
<p>Mit einem kleinen Script l&auml;sst sich das bequem auswerten:</p>
<pre>
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")
</pre>
<p>Da das Script so kurz ist, kann man es auch als 
<a href="/blog/files/cpucores.txt">Einzeiler</a>verwenden. Zum Schluss noch ein paar Beispielausgaben des Scripts:</p>
<pre>
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")
</pre>
</div>
</content>
</entry>
<entry>
<title type="html">base64 f&uuml;r SMTP-Auth und HTTP Basic authentication</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/05/26/base64_f_uumlr_smtp-auth_und_http_basic_authentication/index.html" />
<id>http://localhost/please/edit/me/archives/2011/05/26/base64_f_uumlr_smtp-auth_und_http_basic_authentication/index.html</id>
<published>2011-05-26T23:15:58+01:00</published>
<updated>2011-05-26T23:15:58+01:00</updated>
<category term="http" />
<category term="smtp" />
<category term="python" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>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.</p>
<h4>SMTP-Auth</h4>
<p>Hier der Ausschnitt eines SMTP-Dialogs mit PLAIN-Authentication:</p>
<pre>
$ 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
</pre>
<p>Nach RFC4616 besteht die Zeichenkette f&uuml;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&uuml;ck dekodieren:</p>
<pre>
$ python -c "import base64;print \
&gt; base64.encodestring('mail1\0mail1\0saslpw')"
bWFpbDEAbWFpbDEAc2FzbHB3

$ python -c "import base64;print \
&gt; base64.decodestring('bWFpbDEAbWFpbDEAc2FzbHB3')" \
&gt; |tr \\000 /
mail1/mail1/saslpw

</pre>
<h4>HTTP basic access authentication</h4>
<p>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:</p>
<pre>
GET /index.html HTTP/1.1
Host: www.domain.de
Authorization: Basic dzE6aHRwdw==

</pre>
<p>Auch hier nutzen wir wieder Python, um manuell zu en- und dekodieren.</p>
<pre>
$ python -c \
&gt; "import base64;print base64.encodestring('w1:htpw')"
dzE6aHRwdw==

$ python -c \
&gt; "import base64;print base64.decodestring('dzE6aHRwdw==')"
w1:htpw

</pre>
</div>
</content>
</entry>
<entry>
<title type="html">Apache hat keine freie Semaphore</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/05/25/apache_hat_keine_freie_semaphore/index.html" />
<id>http://localhost/please/edit/me/archives/2011/05/25/apache_hat_keine_freie_semaphore/index.html</id>
<published>2011-05-25T00:35:23+01:00</published>
<updated>2011-05-25T00:35:23+01:00</updated>
<category term="apache" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Das ist auch ein kleiner Klassiker, darum sollen dieses Problem und seine L&ouml;sung auch nicht unerw&auml;hnt bleiben. Es kann vorkommen, dass in einem Apache Error-Log die folgende Zeile auftaucht:</p>
<pre>
No space left on device (errno: 28)
</pre>
<p>Eine Pr&uuml;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:</p>
<pre>
could not create private SSLMutex semaphore
</pre>
<p>Das liefert dann auch den entscheidenden Hinweis darauf, dass Apache keinen neuen Semaphor (ein klassisches Werkzeug f&uuml;r IPC) erzeugen kann. Die man-page zu semget() f&uuml;hrt auch diese Fehlerm&ouml;glichkeit auf:</p>
<pre>
# 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.
</pre>
<p>Das sind bei vielen Hosts oft noch die zu niedrigen Standardwerte:</p>
<pre>
# cat /proc/sys/kernel/sem 
250     32000   32      128
</pre>
<p>Die man-page proc(5) liefert uns folgende Infos dazu:</p>
<pre>
   /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.
</pre>
<p>Eine Z&auml;hlung der Semaphore des Users "www" liefert das:</p>
<pre>
# ipcs -s|grep -c www
128
</pre>
<p>Jetzt stoppen wir Apache, l&ouml;schen alle "vergessenen" Semaphore, setzen die Werte h&ouml;her und starten Apache wieder:</p>
<pre>
# ipcs -s|grep www|cut -d\  -f2|xargs -r -n 1 ipcrm -s
# echo '500 64000 32 1024' &gt;/proc/sys/kernel/sem 
</pre>
</div>
</content>
</entry>
<entry>
<title type="html">Logging in der Konsole</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/05/21/logging_in_der_konsole/index.html" />
<id>http://localhost/please/edit/me/archives/2011/05/21/logging_in_der_konsole/index.html</id>
<published>2011-05-21T09:37:23+01:00</published>
<updated>2011-05-21T09:37:23+01:00</updated>
<category term="shell" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Dieser Post zeigt ein paar M&ouml;glichkeiten, wie man Befehle oder Ausgaben in einer Shell-Session mitschneiden kann.</p>
<p>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&uuml;r Farben, f&uuml;r Zeilen Editierung (Backspace, Tab, Return etc). Wie man mittels vi dieses Log von Steuerzeichen befreit, w&uuml;rde diesen Beitrag sprengen.</p>
<p>Als Alternative kann man sich auch nur die Textausgabe von Programmen in ein Logfile packen. Hier ein Beispiel:</p>
<pre>
$ avscan -a . 2&gt;&1 |tee -a log.avscan
</pre>
<p>Wenn man ein Logging mit Timestamp der einzelnen Zeilen braucht, kann man so etwas machen:</p>
<pre>
$ /opt/drweb/drweb -al . 2&gt;&1 |tai64n |tee -a log.drweb
@400000004c5bbe8b1d775b9c Dr.Web (R) Scanner for Linux
@400000004c5bbe8b1e3010c4 Copyright (c) Igor Daniloff,
</pre>
<p>Das Tool tai64n geh&ouml;rt zu der Softwaresuite 
<a href="http://cr.yp.to/daemontools.html">daemontools von Dan Bernstein</a>. Hier f&uuml;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:</p>
<pre>
$ tai64nlocal &lt;log.drweb |tail -1
2010-08-06 09:43:03.225062500 2009_02_12-ftp.log.gz - Ok
$ 
</pre>
<p>Man kann sich den "Live-Stream" auch direkt bei der Ausgabe wieder konvertiert anzeigen lassen:</p>
<pre>
$ /opt/drweb/drweb -al . 2&gt;&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,
</pre>
<p>Wenn man mit sehr viel Daten bei der Ausgabe rechnet und vielleicht nur den letzten Teil haben m&ouml;chte, dann kann man so eine Zeile nutzen:</p>
<pre>
$ /opt/drweb/drweb -al . 2&gt;&1 |tee /dev/stderr \
  |multilog t s10000 n20 ./logdir
</pre>
<p>Diese Zeile zeigt die Programmausgabe kontinuierlich an und schreibt bis 20 maximal 10 KB gro&szlig;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.</p>
</div>
</content>
</entry>
<entry>
<title type="html">access_log-Statistiken mit awk</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/05/20/access_log-statistiken_mit_awk/index.html" />
<id>http://localhost/please/edit/me/archives/2011/05/20/access_log-statistiken_mit_awk/index.html</id>
<published>2011-05-20T08:00:18+01:00</published>
<updated>2011-05-20T08:00:18+01:00</updated>
<category term="shell" />
<category term="apache" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Heute gibt's nur kleine Einzeiler. Ein Klassiker zum Anzeigen der IP-Adressen eines Apache access_log, letzte 1000 Zugriffe und sortiert nach H&auml;ufigkeit der Zugriffe:</p>
<pre>
tail -n 1000 access_log | awk \
'{f[$1]++}END{for(g in f)print f[g]" "g}' \
| sort -n | tail -n 5
</pre>
<p>M&ouml;chte man nach der angefragten Datei sortieren, muss man '$1' durch '$7' ersetzen, f&uuml;r Sortierung nach Return Code '$9'.</p>
<pre>
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
</pre>
<p>Das sortiert die Zeilen mit 404 Return Code ("File Not Found") und gibt dabei die angeforderte Datei und den Referer an.</p>
<pre>
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
</pre>
<p>Statt 404 werden hier alle 30x Redirects sortiert.</p>
</div>
</content>
</entry>
<entry>
<title type="html">Interaktionen mit expect</title>
<author>
<name>Frank W. Bergmann</name>
</author>
<link rel="alternate" type="text/html" href="http://localhost/please/edit/me/archives/2011/05/19/interaktionen_mit_expect/index.html" />
<id>http://localhost/please/edit/me/archives/2011/05/19/interaktionen_mit_expect/index.html</id>
<published>2011-05-19T17:44:08+01:00</published>
<updated>2011-05-19T17:44:08+01:00</updated>
<category term="shell" />
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Auch wenn die "gro&szlig;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.</p>
<p>Die man-page zu expect erkl&auml;rt die Grundlagen. Hier ist ein Beispiel f&uuml;r die Verwendung von expect aus einem bash-Script heraus:</p>
<pre>
&gt; 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 &lt;&lt;EOF |expect -|egrep 'Disk State:|State :|s status is'
match_max 65536
spawn telnet $IP
expect "name:"
send "admin\n"
expect "passwd:"
send "$PASS\n"
expect "ACSCLI"
send "$CMD\n"
#interact -nobuffer -re "Disk State:"
expect "ACSCLI"
#send_user "output: $expect_out(buffer)"
send "quit\n"
close
EOF
</pre>
<p>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&uuml;rlich auch "reine" expect-Scripts schreiben.</p>
</div>
</content>
</entry>
</feed>

