June 24, 2007

flets squareへのroute

今さらなことだけれど、flets squareへのroutingを手でいじったりちょくちょく確認するのが面倒なので、スクリプトでも書いて勝手に更新するようにしてみた。

#! /usr/bin/env ruby
#

require 'open-uri'
require 'htree'
require 'rexml/document'
require 'tempfile'

scriptfile = '/usr/local/sbin/flets-route.sh'
pppdev = 'ppp1'

ht = HTree.parse(open('http://routing.flets/routing.html').read)
xml = REXML::XPath.match(ht.to_rexml,'/html/body/text()')
tmp = Tempfile.new('flets-route')
fp = tmp.open
fp.printf("#! /bin/sh\n" \
"\n" \
"if [ \"x$1\" = \"xup\" ]; then\n" \
" OP=\"add\"\n" \
"else\n" \
" OP=\"del\"\n" \
"fi\n")
lines = xml[0].to_s.split("\n").grep(/\ARoute\d+=/)
exit(1) if lines.empty?
lines.each do |line|
if line =~ /Route\d+=Add,((?:\d{1,3}\.){3}\d{1,3}),((?:\d{1,3}\.){3}\d{1,3})/
then
fp.printf("/sbin/route $OP -net %s netmask %s dev $2\n", $1, $2)
end
end
fp.close

updated = false
if File.exist?(scriptfile) then
system("diff #{scriptfile} #{fp.path} > /dev/null")
if $? != 0 then
system("#{scriptfile} down #{pppdev}")
File.rename(scriptfile, "#{scriptfile}.#{Time.now.strftime('%Y%m%d')}")
updated = true
end
else
updated = true
end
if updated then
File.rename(fp.path, scriptfile)
File.chmod(0755, scriptfile)
system("#{scriptfile} up #{pppdev}")
end

cronにでも一日一回チェックするように仕込んどけばおk。動かす前にflets squareへ接続できるようにしておく必要はあるけど、そのあたりの設定はぐぐると山ほど出てくるので割愛。出来たファイルは/etc/ppp/{ip -up.d,ip-down.d}もしくはそれに類似するものから呼ぶようにしておけば、rebootなりなんかの都合でpoff/ponする必要があっ たりしても問題なし。

June 21, 2007

PostgreSQL x PAM x syslog

DBへのアクセスにPAMを使うように設定したんだけど、どうも不可解なログを残す。

Jun 20 06:33:19 cosmos .168.2.201(50039) authentication: pam_succeed_if: require
ment "user ingroup db" was met by user "tagoh"

まずpam_succeed_if.soがどんな感じでsyslogにログを吐いているかを見てみた。

int
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
...
if(!quiet_succ)
log_error(LOG_INFO,
"requirement \"%s %s %s\" "
"was met by user \"%s\"",
left, qual, right, user);
...
}

そしてlog_error()が

#define MODULE "pam_succeed_if"

...

static void
log_error(int priority, const char *fmt, ...)
{
va_list va;
char *fmt2;
fmt2 = malloc(strlen(fmt) + strlen(MODULE) + 3);
va_start(va, fmt);
if (fmt2 == NULL) {
vsyslog(LOG_AUTHPRIV | priority, fmt, va);
} else {
snprintf(fmt2, strlen(fmt) + strlen(MODULE) + 3,
"%s: %s", MODULE, fmt);
vsyslog(LOG_AUTHPRIV | priority, fmt2, va);
free(fmt2);
}
va_end(va);
}

という具合になっている。このことから、実際にpam_succeed_if.soがsyslogに対して送っているのはpam_succeed_if: ...以降。日付およびホスト名はその先で勝手につけられる。問題はどのプロセスがそれを送ってよこしたのか、という部分なんだけど、.168.2.201(50039) authentication:はどうみてもなんかおかしい。

ということで、次にvsyslog(3)を覗いてみることにする。

static const char *LogTag; /* string to tag the entry with */
...
extern char *__progname; /* Program name, from crt0. */
...
void
vsyslog(pri, fmt, ap)
int pri;
register const char *fmt;
va_list ap;
{
...
if (LogTag == NULL)
LogTag = __progname;
if (LogTag != NULL)
fputs_unlocked (LogTag, f);
if (LogStat & LOG_PID)
fprintf (f, "[%d]", (int) __getpid ());
if (LogTag != NULL)
{
putc_unlocked (':', f);
putc_unlocked (' ', f);
}
/* Restore errno for %m format. */
__set_errno (saved_errno);
/* We have the header. Print the user's format into the
buffer. */
vfprintf (f, fmt, ap);
/* Close the memory stream; this will finalize the data
into a malloc'd buffer in BUF. */
fclose (f);
...
static void
internal_function
openlog_internal(const char *ident, int logstat, int logfac)
{
if (ident != NULL)
LogTag = ident;
...
}

とこんな感じになっていて、openlog(3)されていない場合はそのプログラムの名前を使いましょう、ということになっている。で、pam_succeed_if.soの方はと言うと、openlog(3)は一切使っていない。よってPAMを呼び出したアプリケーション依存ということになる。

では、次にPostgreSQLの方はというとopenlog(3)を呼んでいるのは一箇所のみ。backend/utils/error/elog.c内のwrite_syslog()。

static void
write_syslog(int level, const char *line)
{
static unsigned long seq = 0;
int len;
/* Open syslog connection if not done yet */
if (!openlog_done)
{
openlog(syslog_ident ? syslog_ident : "postgres",
LOG_PID | LOG_NDELAY | LOG_NOWAIT,
syslog_facility);
openlog_done = true;
}
...

つまり、一度もsyslogへログを吐こうとしてなければopenlog(3)は呼ばれない。

postgresql.confの中にlog_destinationというパラメータがあって(少なくともDebian環境上では)デフォルトがstderrになっている。根本的な解決方法としては、これによらずopenlog(3)を呼べ、ということになるんだけど、手っ取り早くworkaroundで済ますなら、このlog_destinationsyslogに変える。そうすると

Jun 20 23:52:07 cosmos postgres[9371]: pam_succeed_if: requirement "user ingroup
db" was met by user "tagoh"

という具合に期待どおりの結果になった。

June 16, 2007

シリアルコンソールを仕込んでみる

最近どうも安定して動かない上に、CPU load食いまくってsshで入るのも難儀なことが多く、その度にvmware-server-consoleを起動させては、ごにょごにょとあれこれや るはめになる。また、セキュリティ上外から902番ポートへ繋げないようにしてるので、sshでport forwardしてとかまあなんつーか面倒くさいことこの上ない。そこで、vmware上のシリアルポートをhostのttyへマップさせ、シリアルコン ソール替わりに使うことにした。

まず、各VMの設定を変更する。シリアルポートをひとつずつ追加し、Use named pipeを選択、pipeの名前は後で識別しやすいように/tmp/serial-hostname portとした。また、今回このシリアルポートはhostから使うので、This end is the serverおよびThe other end is an applicationを選択。あとは、/etc/inittabにgetty経由でログインできるように修正。Debianの場合はすでにコメントアウトされた行があるので、それを有効にするだけでよい。

次にhost側。先ほど指定したnamed pipeはhost上に作られるけど、そのままだとよくあるterminal系のアプリでは使えないので、socatを使ってptyに変換した。ついでにそのまま接続しちゃうように次のようなスクリプトを書いた。

#! /bin/sh

set -e

if [ $# -eq 0 ]; then
echo "$0 "
exit 1
fi

PORT=$2
if [ "x$PORT" = "x" ]; then
PORT=0
fi

if [ ! -S /tmp/serial-$1$PORT ]; then
echo "Unknown hostname"
exit 1
fi

socat unix-connect:/tmp/serial-$1$PORT pty:link=/tmp/ttyv$1$PORT,raw,echo=0,waitslave &
SOPID=$!
if ls /proc/$SOPID > /dev/null 2>&1; then
while [ ! -h /tmp/ttyv$1$PORT ]; do sleep 1; done
cu -l /tmp/ttyv$1$PORT
else
echo failed.
fi

June 13, 2007

フォントサイズが小さくなった

FC6 からF7へアップグレードした後Firefoxのあらゆるフォントが小さくなった。gnome-font-propertiesとかでDPIの設定をいじ るとたしかにFirefox上でも変化するんだけど、当然ながら他のGNOMEアプリも影響するため、Firefoxで丁度よいサイズになると他の GNOMEアプリ上ではでかすぎて話にならない。

解決策としては、about:configを開きlayout.css.dpiに0(初期値は-1)を設定し、再起動すると以前のサイズに戻った。