Hatena::ブログ(Diary)

N.E.E.T―Never Ending Engineer’s Tragicomedy別館 このページをアンテナに追加 RSSフィード

2008年10月02日(木)

RPMマクロ

便利に使えるRPMマクロたち

%define foo bar

%fooをbarに定義するマクロ.cpp(1)の#defineみたいなもの.

後から上書きできる.

%define foo 1
%define foo 2
%foo  # => 2
%{?name:expr}

nameが定義されていたらexprを評価.cpp(1)の#ifdefみたいなもの.

%{!?name:expr}

nameが定義されていなかったらexprを評価.cpp(1)の#ifndefみたいなもの.

%(expr)

exprの中身を/bin/shで実行する.評価結果は標準出力に出力された文字列となる.cpp(1)にはこんな変態マクロは無い.

組み合わせても使える
%{!?uname:%define uname %(uname)}
%ifもあるよ

condは,少なくとも 0 or 1 の場合に,期待通りに動くようだ.

%if cond
commands
%endif

RPMマクロの働きの調べ方

RPMのspecファイル中に現れる%{...}という形の式は,rpm(8)がマクロと判断して評価する.RedHatベースのシステムには,いくつか定義済みのマクロがあり,これらは/usr/lib/rpm/macrosファイルを調べる事で確認することができる.

しかし,わからないマクロが出てくるたびにいちいちこのファイルを読むのはとても面倒である.そんなときのために,rpm(8)には--evalオプションがある.これを使うと,マクロがどのように展開されるのか確認することができる.

実行例
% rpm --eval '%configure'

evalオプションを複数書くこともできる.この場合,オプションの順番通りに評価が行われる.

% rpm --eval '%{!?python_sitelib: %define python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}' \
      --eval '%{python_sitelib}'
/usr/lib/python2.3/site-packages

RHELのリリース番号を調べる

RedHatディストリビューション(RHEL4, CentOSなど)では,リリースパッケージの識別用にRPMパッケージが導入されている.このリリースパッケージは,"redhat-release" をProvideしている.RHELであればこの識別子を調べることで,そのシステムのリリース番号を調べる事ができる.

% rpm -q --provides `rpm -q --whatprovides redhat-release`

または,もっと単純に以下のようにしても良い.

% rpm -qi redhat-release

この識別子は,例えば,自分でRPMパッケージを作る際,「このRPMは,RHELの特定のリリースにのみインストールを許可したい」という制限を課すために使うことができる.例えば,specファイル中で "Required: redhat-release >= 5.0" のように表記することでこのような動作が実現できる.

2008年06月17日(火)

PAM設定ファイルは,どれが読み込まれるのか?

Linux-PAM(pam(8))が入っているような,いまどきの普通のシステムでは,/etc/pam.dディレクトリ(または/etc/pam.confファイル)が存在する.各プログラム(デーモンなど)が認証処理を行う必要があるときに,ここから設定ファイルを読み込んで,PAMを通じて必要な処理を行う.例えば,sshdの場合,/etc/pam.d/sshdを読み込んで認証処理を行う.

ところで,各プログラムはどのようにして自身が読み込むファイル名(サービス名)を決めているのだろう? 結論を先に書くと,各プログラムがpam_start(3)を呼ぶ時の第一引数(サービス名)によって決まる.

例えば,OpenSSH(sshd)のコードを追ってみると,次のようなコードが見つかる.

auth-pam.c
pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);

SSHD_PAM_SERVICEは #define SSHD_PAM_SERVICE __progname と定義されていて,結局のところこれはsshd.cではargv[0]のbasename(ファイル名の部分)である.つまり,自身のファイル名となっていることがわかる.

まとめ

  • PAMを用いるプログラムが読み込むPAM設定ファイルは,pam_start(3)の第一引数(サービス名)によって決まる
  • サービス名は,OpenSSHのsshdではプログラム自身のファイル名となっている
  • そういう事情なので,sshdのファイル名を変更した場合は,/etc/pam.d/sshdも名前を変更しよう
  • 他のプログラムでは当然事情が異なる.不明な場合はpam_start(3)を呼んでいる所を探して調べよう

2008年06月15日(日)

portsnapを使ってportsツリーを更新

csupを使うかわりに,portsnapを使ってportsツリーを更新することにしました.

手順は以下の通りです.「BSD にくびったけ - portsnap」にすばらしい解説記事があるので,ここを参考に作業しました.ほとんどこの記事の通りです.

手順

使い始める時にやること

(1) とりあえずportsnap fetch

% sudo portsnap fetch

(2) 次にportsnap extract

% sudo portsnap extract

(3) 最後にportsnap update

% sudo portsnap update

(4) 更新されたportsパッケージを確認

% sudo portversion -vL=

(5) 必要に応じてアップデート

とりあえず全部更新な場合は次のような感じで.

% sudo portupgrade -aRP
2回目以降にやる事

(1) portsnap fetch && portsnap update

% sudo portsnap fetch && sudo portsnap update

portsパッケージの確認や更新は同じ.

/etc/crontabに自動更新を仕込む

いちいち自分でportupgradeするのもだるい.というか,このくらい自動でアップデートして頂きたい.こんな事を毎回手動でやっていたらIT土方そのものである.そんなわけで.スクリプトを書いてcrontabに仕込むことにした.

まず,次のようなスクリプトを書いて/usr/local/sbinあたりに放り込んでchmod 755する.

  • /usr/local/sbin/update-ports-cron.sh
#!/bin/sh
# $Id: update-ports-cron.sh 204 2008-06-15 11:30:39Z genta $
( /usr/sbin/portsnap fetch && /usr/sbin/portsnap update ) 2>&1 >/dev/null
/usr/local/sbin/pkgdb -F

echo "---- portversion:"
/usr/local/sbin/portversion -vL=
echo

echo "---- portupgrade:"
/usr/local/sbin/portupgrade -aRP --batch
echo

echo -n "Finished at: "
LANG=C date

次に,/etc/crontabに以下の行を追加.

0 5 * * * root /usr/local/sbin/update-ports-cron.sh

これでうまく行くんじゃないだろうか.いくといいな.

参考

freebsd-updateを使いたければRELEASEにしとかないとだめ

freebsd-update(8)を使ってシステムをアップデートしたい人は,セキュリティブランチ(RELENG_7_0等)でcsupしてビルドしましょう.freebsd-update(8)はRELEASEのみをサポートしているので,うっかりSTABLEをビルドするとはまります.

いきさつ

RELEASE-6.2なシステムを7.0-STABLE(RELENG_7)に上げた.

% uname -a
FreeBSD yourhost.yourdomain 7.0-STABLE FreeBSD 7.0-STABLE #1: Sun Jun 15 02:29:39 JST 2008
root@yourhost.yourdomain:/usr/obj/usr/src/sys/GENERIC  i386

次回からは,自分でちまちまとビルドしたりといった作業は避けたかったので,freebsd-update(8)を試す.ところが,下記のようなよくわからないエラーとなりだめ.

% sudo freebsd-update fetch
Looking up update.FreeBSD.org mirrors... 1 mirrors found.
Fetching public key from update1.FreeBSD.org... failed.
No mirrors remaining, giving up.

素直にエラーメッセージだけを読むと,update1.freebsd.orgが落ちているように読めるが,pingは通るし当該サーバが落ちたという情報も特に見当たらない.

そこで,エラーメッセージググるFreeBSD PR: misc/12137に行き着いた.がーん,これだ.ショック.

あと,よく見るとfreebsd-update(8)のmanにも「RELEASEしかサポートしてないもんね」と書いてあった.がーん.

回避

(1) RELENG_7_0でビルドし直す.RELENG_7_0を指定してcsupし,通常の手順でビルド (/usr/src/UPDATINGを参照)

(2) 再度freebsd-update

これでうまくアップデートできるようになった.しかし,あまりSTABLEとの差が大きかったらはまったかもしれないので,お勧めはできない.

参考

2008年06月09日(月)

WWW::Mechanize(Rubyの)で一部のフォームが取れない問題

どうも,well-formedじゃないHTMLの場合に,フォームの一部を取れないみたい.例えば,以下のようなフォームがあるときにbarが取れない(WWW::Mechanize#page.forms.first.field('bar').nil? == trueになる).

<p>
<form>
<input name="foo">
</p>
<input name="bar">

検索してみたけど情報が無い.みんな困っていないのだろうか?

まだ対策できていないけど,テストだけ張っておく.これがpassすれば問題解決.

#!/usr/local/bin/ruby
# $Id$
require 'rubygems'
require 'mechanize'
require 'logger'
require 'webrick'
require 'test/unit'
require 'ruby-debug'

class DumbHTTPD
  class Servlet < WEBrick::HTTPServlet::AbstractServlet
    @@tmpl = lambda do |val|
      <<_EOT_
<html>
<body>
<h1>Fill out below form:</h1>
<p>
  <form action="/" method="POST">
  <input type="text" name="foo" value="#{val['foo']}">
</p>
  <input type="text" name="bar" value="#{val['bar']}">
  <input type="submit" value="save">
</form>
</body>
</html>
_EOT_
    end
    def do_GET(req, res)
      res['Content-Type'] = 'text/html; charset=utf-8'
      res.body = @@tmpl.call({
        'foo' => 'Hello world',
        'bar' => 'hoge',
      })
      return res
    end
    def do_POST(req, res)
      res['Content-Type'] = 'text/html; charset=utf-8'
      res.body = @@tmpl.call(req.query)
      return res
    end
  end

  attr_accessor :webrick, :runtime, :bindaddr, :port
  def initialize(bindaddr, port)
    self.bindaddr, self.port = bindaddr, port
  end

  def init_webrick
    self.webrick = WEBrick::HTTPServer.new(
      :BindAddress => self.bindaddr,
      :Port => self.port)
    self.webrick.mount('/', Servlet)
  end

  def start
    self.init_webrick
    self.runtime = Thread.new(self.webrick) {|w| w.start}
    return self
  end

  def stop
    self.runtime.kill.join
    self.webrick.shutdown
    return self
  end
end


class TC_Mech < Test::Unit::TestCase
  attr_accessor :agent, :servlet
  def setup
    self.agent = WWW::Mechanize.new {|a| a.log = Logger.new($STDERR) }
    self.agent.max_history = 1
    self.agent.user_agent_alias = 'Windows IE 6'

    self.servlet = DumbHTTPD.new('localhost', 10182).start
  end

  def teardown
    self.servlet.stop
  end

  def test_scrape_not_wellformed_html
    page = self.agent.get('http://localhost:10182')
    form = page.forms.first
    {'foo' => 'Hello world',
     'bar' => 'hoge',
    }.each do |k, v|
      field = form.field(k)
      assert(!field.nil?, "form field '#{k}' is not exists")
      assert_equal(v, field.value, "form field '#{k}'.value != '#{v}'")
    end
  end
end

対処法の考察(メモ)

WWW::Mechanize::Page#formsは,最初の一回呼び出された時にHpricot.parseしてsearch('form')して,出てきたHpricot::Elements分だけformを作って(WWW::Mechanize::Pageのインスタンス変数に)キャッシュする.んだけども,Hpricotは上記のような壊れたHTMLを読む時,後続のinputを無視してしまう.

だけど,Hpricot的には多分悪くない動作.多分,WWW::Mechanizeで対策するべきで,Mechはplaggable_parserという機構がありHTMLパーサを動的に差し替える事が可能.これを使って「ゆるくHTMLフォームを解釈するWWW::Mechanize::Pageの子孫クラス」を適当に作って以下のようにすればよい.

class WWW::Mechanize::LamePage < WWW::Mechanize::Page
  def initialize(uri=nil, response=nil, body=nil, code=nil)
    super(uri, response, body, code)
  end

  def forms
    # ここでformsを再定義
  end
end

agent = WWW::Mechanize.new
agent.pluggable_parser.html = WWW::Mechanize::LamePage  # 標準のパーサを差し替え
# 後は普通に使う

と,対策手法はわかっているんだけど,Hpricotの使い方が難しくてなかなか進みません…….

追記 (2009/2/24)

WWW::Mechanize 0.9.0で追試したところ,本エントリで触れた問題は解決していた.よかった.

どうやら,HTMLパーサがHpricotからNokogiriに変わったことで,このような問題がなくなった模様.

2008年05月27日(火)

Twitterの自動follow返しをRubyで

Twitter でイチイチ follow するのが面倒くさい んだけど自前でメールサーバも立ててない - Djangoへの片思い日記 関連.

Rubyだとこんな感じかな? 以下,付属ライブラリのみ使用.

自前のIMAP4サーバに対してしかテストしてないけど,たぶんGmailでも動くんじゃないかと思う.

#!/usr/local/bin/ruby
require 'net/imap'
require 'open-uri'

# IMAP4 configuration:
SERVER = 'imap.gmail.com'
USER = 'exampleuser@gmail.com'
PASSWD = 'gmail_password_here'

class Twitter
  USER = 'twitter_username_here'
  PASSWD = 'twitter_password_here'
  TwitterURI = 'http://twitter.com/friendships/create/%s.json'
  def self.add(id)
    open(TwitterURI % [id], :http_basic_authentication => [USER, PASSWD]).read
  end
end

imap = Net::IMAP.new(SERVER, 993, true)
imap.login(USER, PASSWD)
imap.select('INBOX')

imap.search(['FROM', 'noreply@twitter.com',
             'SUBJECT', 'is now following you on Twitter!', 'UNSEEN']).
each do |num|
  data = imap.fetch(num, 'BODY[TEXT]')
  body = data[0].attr['BODY[TEXT]']
  Twitter.add(id = body.match(%r|http://twitter\.com/(\w+)|).to_a[1])
  imap.store(num, '+FLAGS.SILENT', [:Seen])
  puts "add #{id}"
end
imap.close

2008年05月12日(月)

flow-tools 0.66用パッチ

Linux (Debian SargeとかCentOS)にてflow-tools 0.66(NetFlowコレクタ)のコンパイルが通らなかったので,いくつか修正してパッチファイル作った.

直したのは,ANSI C非互換のキャストの使い方をしていた部分と,ブロックの最後にラベルがあるとエラーになる問題.

前者は例えば以下のようなもの.

  /* だめな例 */
  void *foo = bar;
  (char *)foo += 2; /* 左辺値はキャストしたらだめー */

  /* 修正後 */
  void *foo = bar;
  foo = (char *)foo + 2;

後者は例えば以下のようなもの.

  /* だめな例 */
  for (;;) {
    do_something1();
    if (cond) goto skip;
    do_something2();
  skip: /* これだめ */
  }

  /* 修正後 */
  for (;;) {
    do_something1();
    if (cond) goto skip;
    do_something2();
  skip:
    ; /* とにかく何か文があればいいらしい */
  }

パッチ (flow-tools-0.66-patch)

flow-tools-0.66ディレクトリ以下で patch -p0 < flow-tools-0.66-patch てな具合にするとよし.

diff -ru -x '*.Po' flow-tools-0.66.orig/lib/ftchash.c flow-tools-0.66/lib/ftchash.c
--- flow-tools-0.66.orig/lib/ftchash.c	2003-02-13 11:38:41.000000000 +0900
+++ flow-tools-0.66/lib/ftchash.c	2008-05-12 16:32:07.000000000 +0900
@@ -326,7 +326,7 @@
       (char*)ftch->traverse_chunk->base+ftch->traverse_chunk->next) {
 
       ret = ftch->traverse_rec;
-      (char*)ftch->traverse_rec += ftch->d_size;
+      ftch->traverse_rec = (char*)ftch->traverse_rec + ftch->d_size;
       return ret;
 
     } else {
diff -ru -x '*.Po' flow-tools-0.66.orig/lib/ftio.c flow-tools-0.66/lib/ftio.c
--- flow-tools-0.66.orig/lib/ftio.c	2003-02-24 09:51:47.000000000 +0900
+++ flow-tools-0.66/lib/ftio.c	2008-05-12 16:29:11.000000000 +0900
@@ -2267,7 +2267,7 @@
         break;
 
       nleft -= nread;
-      (char*)ptr += nread;
+      ptr = (char*)ptr + nread;
   }
   return (nbytes - nleft);
 } /* readn */
@@ -2292,7 +2292,7 @@
       return(nwritten); /* error */
 
     nleft -= nwritten;
-    (char*)ptr += nwritten;
+    ptr = (char*)ptr + nwritten;
   }
   return(nbytes - nleft);
 } /* writen */
diff -ru -x '*.Po' flow-tools-0.66.orig/lib/fttlv.c flow-tools-0.66/lib/fttlv.c
--- flow-tools-0.66.orig/lib/fttlv.c	2003-02-13 11:38:43.000000000 +0900
+++ flow-tools-0.66/lib/fttlv.c	2008-05-12 16:31:31.000000000 +0900
@@ -68,10 +68,10 @@
   }
 
   bcopy(&t, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&len, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&v, buf, 4);
 
@@ -107,10 +107,10 @@
   }
 
   bcopy(&t, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&len, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&v, buf, 2);
 
@@ -145,10 +145,10 @@
   }
 
   bcopy(&t, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&len, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&v, buf, 1);
 
@@ -183,10 +183,10 @@
   }
 
   bcopy(&t, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&len, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(v, buf, len);
 
@@ -230,16 +230,16 @@
     return -1;
 
   bcopy(&t, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&len, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&ip, buf, 4);
-  (char*)buf += 4;
+  buf = (char*)buf + 4;
 
   bcopy(&ifIndex, buf, 2);
-  (char*)buf += 2;
+  buf = (char*)buf + 2;
 
   bcopy(name, buf, n);
 
@@ -287,19 +287,19 @@
   }
 
   bcopy(&t, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&len, buf, 2);
-  (char*)buf+= 2;
+  buf = (char*)buf + 2;
 
   bcopy(&ip, buf, 4);
-  (char*)buf += 4;
+  buf = (char*)buf + 4;
 
   bcopy(&entries, buf, 2);
-  (char*)buf += 2;
+  buf = (char*)buf + 2;
 
   bcopy(ifIndex_list, buf, esize);
-  (char*)buf += esize;
+  buf = (char*)buf + esize;
 
   bcopy(name, buf, n);
 
diff -ru -x '*.Po' flow-tools-0.66.orig/src/flow-cat.c flow-tools-0.66/src/flow-cat.c
--- flow-tools-0.66.orig/src/flow-cat.c	2003-04-03 03:03:01.000000000 +0900
+++ flow-tools-0.66/src/flow-cat.c	2008-05-12 16:33:59.000000000 +0900
@@ -551,7 +551,7 @@
         break;
 
 next_file:
-
+      ;
     }  /* FOREACH filename in dir */
 
   } /* foreach dir bundle */
diff -ru -x '*.Po' flow-tools-0.66.orig/src/flow-dscan.c flow-tools-0.66/src/flow-dscan.c
--- flow-tools-0.66.orig/src/flow-dscan.c	2003-04-03 03:03:01.000000000 +0900
+++ flow-tools-0.66/src/flow-dscan.c	2008-05-12 16:34:28.000000000 +0900
@@ -560,7 +560,7 @@
       ager(&ds, total_flows32);
 
 skip2:
-
+    ;
 
   } /* while rec */
 
@@ -805,6 +805,7 @@
   fterr_info("ager: reset hash run");
 
 skip3:
+  ;
 
 } /* ager */
 
diff -ru -x '*.Po' flow-tools-0.66.orig/src/flow-fanout.c flow-tools-0.66/src/flow-fanout.c
--- flow-tools-0.66.orig/src/flow-fanout.c	2003-04-04 11:24:40.000000000 +0900
+++ flow-tools-0.66/src/flow-fanout.c	2008-05-12 16:35:39.000000000 +0900
@@ -809,7 +809,7 @@
       } /* fte.buf_size */
     
 skip1:
-
+      ;
     } /* if FD_ISSET */
 
     if (sig_quit_flag) {
diff -ru -x '*.Po' flow-tools-0.66.orig/src/flow-receive.c flow-tools-0.66/src/flow-receive.c
--- flow-tools-0.66.orig/src/flow-receive.c	2003-04-03 03:03:02.000000000 +0900
+++ flow-tools-0.66/src/flow-receive.c	2008-05-12 16:34:46.000000000 +0900
@@ -753,7 +753,7 @@
       } /* for */
 
 skip1:
-
+      ;
     } /* if FD_ISSET */
 
   } /* while 1 */

こういうのCodeReposに上げてもいいのかなあ…….

2008年04月28日(月)

リストのリストから,ハッシュのリストを作る

「怠慢はプログラマの美徳」というけれど - kなんとかの日記 を見て,

例えば、スクリプト言語で次のような Hash や Dict を書いたとする。

data = [
  {'name'=>'Foo', 'age'=>20, 'email'=>'foo@mail.com'},
  {'name'=>'Bar', 'age'=>21, 'email'=>'bar@mail.net'},
  {'name'=>'Baz', 'age'=>22, 'email'=>'baz@mail.org'},
]

もしこれをみて何も感じないのであれば、スクリプト言語屋といえど Java 屋を笑うことはできない。本質的でない記述に嫌悪感を感じるセンスがあれば、同じキーが何度も現れていることを「めんどくさい」と感じるはずだ。そして、こんなふうに書けないだろうかと一度は思うはずだ。

data = %h{
  ['name', 'age', 'email'],
  ['Foo',   20,   'foo@mail.com'],
  ['Bar',   21,   'bar@mail.net'],
  ['Baz',   22,   'baz@mail.org'],
}
「怠慢はプログラマの美徳」というけれど - kなんとかの日記

何だかむずむずしてきたので,リストのリストからハッシュのリストを生成するコード片を書いてみた.

#!/usr/local/bin/ruby
require 'pp'

class Array
  def to_AoH
    lambda {|keys, columns|
      columns.map! {|column| Hash[*keys.zip(column).flatten] }
    }.call(self.shift, self)
  end
end

table = [
  [:name, :age, :email],
  ['Foo',   20, 'foo@mail.com'],
  ['Bar',   21, 'bar@mail.net'],
  ['Baz',   22, 'baz@mail.org'],
]

pp table.to_AoH

実行結果はこんな感じ.

% ./table2arrayOfHash.rb
[{:email=>"foo@mail.com", :name=>"Foo", :age=>20},
 {:email=>"bar@mail.net", :name=>"Bar", :age=>21},
 {:email=>"baz@mail.org", :name=>"Baz", :age=>22}]

でも,こっちの方が好みかなぁ.

#!/usr/local/bin/ruby
require 'pp'

class Array
  def to_AoH(*keys)
    map {|column| Hash[*keys.zip(column).flatten] }
  end
end

aoh = [
  ['Foo', 20, 'foo@mail.com'],
  ['Bar', 21, 'bar@mail.net'],
  ['Baz', 22, 'baz@mail.org'],
].to_AoH(:name, :age, :email)

pp aoh

いや,やはりキーはまず値より先に現れるべきか,と思い直してさらに修正.

#!/usr/local/bin/ruby
require 'pp'

class Array
  def to_AoH(*lists)
    lists.map {|values| Hash[*self.zip(values).flatten]}
  end
end

aoh = [:name, :age, :email].to_AoH(
  ['Foo', 20, 'foo@mail.com'],
  ['Bar', 21, 'bar@mail.net'],
  ['Baz', 22, 'baz@mail.org']
)

pp aoh

各リストをそれぞれメソッドの引数に積んでいるので,最後の要素の後ろにカンマ(',')を書けないところが若干気持ち悪いけど,こんなところかなぁ.

2008年04月26日(土)

テイルズ・エール・ハウス

ピンクの象さんの看板でお馴染みの,テイルズ・エール・ハウスに行ってきました.

このお店は,やたらとクオリティの高いベルギービールが飲める,とても危険なお店です.

店内の様子はこんな感じ


お店に着くや否や,最初からロシュフォール10をオーダするだめ人間なわたし


こちらはマスターに教えていただいた「セント・ベルナンデュス ベリオール」というベルギービール.通称「赤ボウズ」と言うらしい.これがまたアホみたいに美味く,当方のメートルも上がる一方.


マルール12.濃厚な味わいと香り.ロシュフォールよりこちらの方が好きかも.


こちらは「青ボウズ」.腰が抜けるほどうまい.


ごちそうさま!

2008年04月25日(金)

SMTP-AUTH用の証明書を作る

酔っぱらった日は証明書のメンテナンスに限る.

ということで,デフォルトで入ってたSnakeOil証明書に甘んじていた我が家のPostfixを,もう少しましな感じにしようかなと決意する.結局,第四種オレオレ証明書だけどね.

作業手順

/etc/ssl/demoCAができてる事が前提.無い人は/usr/lib/ssl/misc/CA.pl -newcaで.

秘密鍵作る
# cd /etc/ssl
# openssl genrsa -out demoCA/private/`hostname`.key 2048
Generating RSA private key, 2048 bit long modulus
............................................+++
...............................................+++
e is 65537 (0x10001)

作った秘密鍵の中身を確認したければ以下のような感じで.

# openssl rsa -in demoCA/private/`hostname`.key -text
CSRつくる
# openssl req -new -key demoCA/private/`hostname`.key -out csr.pem

OUとかコモンネーム(CN)などを聞かれるので適切に答えていくと,CSRファイルができる.

作ったCSRの中身を確認するには,以下のような感じで.

# openssl req -in csr.pem -text
署名するぜ(by CA)

ここでCAの立場になる.

先ほど作ったCSRをもとに,証明書を発行する.

# openssl ca -in csr.pem -out demoCA/certs/`hostname`.pem -days 3650
Using configuration from /usr/lib/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            de:ad:be:ef:ab:ad:ca:fe
        Validity
            Not Before: Apr 25 00:00:00 2008 GMT
            Not After : Apr 25 00:00:00 2018 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Foreign
            organizationName          = My company
            organizationalUnitName    = My Unit
            commonName                = mail.example.com
            emailAddress              = webmaster@example.com
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                DE:AD:BE:EF:AB:AD:CA:FE:DE:AD:BE:EF:AB:AD:CA:FE:DE:AD:BE:EF
            X509v3 Authority Key Identifier:
                keyid:DE:AD:BE:EF:AB:AD:CA:FE:DE:AD:BE:EF:AB:AD:CA:FE:DE:AD:BE:EF

Certificate is to be certified until Apr 25 00:00:00 2018 GMT (3650 days)
Sign the certificate? [y/n]:

証明書の中身を確認し,問題がなければ y と入力.

Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

これで完了

Postix SMTP-AUTH用設定

main.cf

smtpd_tls_cert_file=/etc/ssl/demoCA/certs/EXAMPLE.pem
smtpd_tls_key_file=/etc/ssl/demoCA/private/EXAMPLE.key

再読み込み

# /etc/init.d/postfix reload
Reloading Postfix configuration...done.

これでSnakeOilから脱却.やったね.

2008年04月12日(土)

VMware上のUbuntuでMozilla Trunkビルド環境を作る

VMware上にUbuntu 7.10環境を構築し,Mozilla Trunk(Minefield)のビルド環境を構築するためのメモ.

環境

  • Ubuntu 7.10 (Gutsy Gibbon)
    • Desktop CDを使いGNOME環境を構築する.
    • 事前にisoイメージを適宜入手しておく.

作業手順 (Ubuntuセットアップ)

VMware上にUbuntu用ゲストOSを作成

ゲストOS作成後,vmxファイルをテキストエディタで開き,以下を追加する.これは,VMware上でUbuntuインストーラを起動させた際,解像度がやたら高くなってしまう問題を回避するため.

svga.maxWidth = "1024"
svga.maxHeight = "768"

D: にUbuntu 7.10のisoイメージをマウントし,普通にインストール再起動する.

まずはアップデート

GUIが好きな人は,タスクトレイ(?)の所にあるアレをクリックしてアップデートしてもよいと思う.

% sudo apt-get update
% sudo apt-get upgrade

一度再起動が必要かも.

Mozillaビルドに必要なパッケージをapt-get install

がんがんapt-get installする.

% sudo apt-get -y install build-essential
% sudo apt-get -y build-dep firefox-3.0
% sudo apt-get -y install cvs
% sudo apt-get -y install libdbus-glib-1-dev
% sudo apt-get -y install libcurl3
% sudo apt-get -y install libcurl4-openssl-dev

生活環境も整える.

% sudo apt-get -y install vim lv
% sudo apt-get -y install subversion zsh openssh-server
% sudo apt-get -y install ddd global

zshが無いと死ぬ人はchshしておく.

VMware toolsをビルドするのに必要なパッケージもインストール

% sudo apt-get install libqt3-headers libqt3-mt-dev
% sudo apt-get install bin86 kernel-package

VMware toolsをここでインストールしてもよいし,しなくてもよい.

私は上記を毎回手で打つのも面倒なので,.sshや.zshenv, .zshrc, .screenrc, ... etc ... を展開する作業とあわせてシェルスクリプトにした.このあたりは各自お好みで.

Mozilla Firefox(Minefield)ビルド手順

ビルド環境を整える

${HOME}/.mozconfigを作る

. $topsrcdir/browser/config/mozconfig
export CC=/usr/bin/gcc
export CXX=/usr/bin/g++

mk_add_options MOZ_CO_PROJECT=browser
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/firefox-build

ac_add_options --enable-application=browser
ac_add_options --enable-default-toolkit=cairo-gtk2

# below are not necessary. do as you like:
ac_add_options --disable-ldap
ac_add_options --disable-postscript
ac_add_options --disable-accessibility
ac_add_options --disable-printing
ac_add_options --disable-composer
ac_add_options --disable-mathml
ac_add_options --disable-svg
ac_add_options --disable-svg-foreignobject
ac_add_options --enable-debug
ac_add_options --enable-optimize=-O

ビルドの度に手でコマンドを打つのも面倒なので,シェルスクリプト書く.

  • build-trunk.sh
#!/bin/sh
# build-trunk.sh
# $Id: build-trunk.sh 87 2008-04-07 08:57:04Z genta $

# BRANCH="-r MOZILLA_1_8_BRANCH"
BRANCH=""
DIRNAME="mozilla_trunk"
LOG=${HOME}/log/build.${DIRNAME}.log
export CVSROOT=':pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot'

# Output to STDOUT and STDERR gose to file ${LOG}
exec 4>&1 5>&2
exec 3>${LOG} 1>&3 2>&3

echo 'Begin building'
LANG=C date

# rotate dir and mkdir
if [ -d ${DIRNAME} ]; then
        if [ -d ${DIRNAME}.old ]; then
                mv ${DIRNAME}.old ${DIRNAME}.trash
                rm -rf ${DIRNAME}.trash
        fi
        mv ${DIRNAME} ${DIRNAME}.old
fi
mkdir ${DIRNAME}; cd ${DIRNAME}

cvs co ${BRANCH} mozilla/client.mk
cvs co ${BRANCH} mozilla/browser/config/mozconfig
mkdir mozilla/firefox-build
cd mozilla

cp ${HOME}/.mozconfig .

make -f client.mk checkout
make -f client.mk build 2>&1

echo 'Build done'
LANG=C date

echo 'Creating gtags'
LANG=C date
gtags -v
htags -saF
echo 'Done'

gtagsとかしている部分はお好みで.

ビルド中のログを出力するためのディレクトリを掘る.

% mkdir ~/log
ビルド
% ./build-trunk.sh

ビルド中のログは~/log/build.mozilla_trunk.logに落ちているので,気になる人は他の端末エミュレータを開いてtail -fしておくとよいと思う.

起動

無事ビルドが終わったら,起動してみる.

% cd mozilla_trunk/mozilla/firefox-build/dist/bin
% ./run-mozilla.sh ./firefox

run-mozilla.sh引数には "./firefox" と,"./" を忘れないように注意.忘れると/usr/bin/firefoxの方が起動したりしてわりと混乱することになる.

デバッガ(ddd)の上でfirefoxを起動するときは以下のようにする.

% ./run-mozilla.sh -g ./firefox-bin

runさせて適当なタイミングでinfo threadsとかして途方に暮れるのもよし.

ssh経由で起動するときは,DISPLAY環境変数を適当に設定しておくとよし.手元にX11が起動していればそれを使ってもいいと思う.

  • SSH端末(putty等)より以下を実行
% env DISPLAY=:0.0 ./run-mozilla.sh ./firefox-bin

これでVMware上でMinefieldが起動する.

GNU Globalで作ったHTMLを閲覧

htagsが~/mozilla_trunk/mozilla/HTML以下にHTMLファイルを作ってくれているので,これをソースコード解析の基点にすることができる.普通にUbuntuの上でWebブラウザを用いて閲覧するか,またはlighttpdとか適当なHTTPdインストールして他のマシンから閲覧してもよい.

lighttpdのセットアップ (おまけ)

public_htmlを用意

% mkdir ~/public_html
% cd ~/public_html
% ln -s ../mozilla_trunk/mozilla/HTML

lighttpdインストールスクリプト

#!/bin/sh
# build-lighttpd.sh -- Build lighttpd environment for reading source code

apt-get install lighttpd

cp lighttpd.user /etc/lighttpd
(cd /etc/lighttpd; patch ) < patch.lighttpd.conf
(cd /etc/lighttpd/conf-available; patch -p1 ) < patch.auth.conf

/usr/sbin/lighty-enable-mod auth
/usr/sbin/lighty-enable-mod userdir

/etc/init.d/lighttpd force-reload
yourname:yourBasicAuthPassword

お好みで.

*** lighttpd.conf.orig  2008-03-12 04:23:02.000000000 +0900
--- lighttpd.conf       2008-04-07 12:03:07.000000000 +0900
***************
*** 63,68 ****
--- 63,69 ----

  ## bind to port (default: 80)
  # server.port               = 81
+ server.port = 10080

  ## bind to localhost only (default: all interfaces)
  ## server.bind                = "localhost"

server.portはお好みで.

  • patch.auth.conf
*** conf-available/10-auth.conf.orig    2008-03-12 04:23:02.000000000 +0900
--- conf-available/10-auth.conf 2008-04-07 12:17:00.000000000 +0900
***************
*** 5,13 ****

  server.modules                += ( "mod_auth" )

! # auth.backend                 = "plain"
! # auth.backend.plain.userfile  = "lighttpd.user"
! # auth.backend.plain.groupfile = "lighttpd.group"

  # auth.backend.ldap.hostname   = "localhost"
  # auth.backend.ldap.base-dn    = "dc=my-domain,dc=com"
--- 5,20 ----

  server.modules                += ( "mod_auth" )

! auth.backend                 = "plain"
! auth.backend.plain.userfile  = "/etc/lighttpd/lighttpd.user"
! auth.backend.plain.groupfile = "lighttpd.group"
!
! auth.require = ( "/" =>
!                ( "method" => "digest",
!                  "realm"  => "Permitted user",
!                  "require" => "valid-user"
!                )
!              )

  # auth.backend.ldap.hostname   = "localhost"
  # auth.backend.ldap.base-dn    = "dc=my-domain,dc=com"

BASIC認証の設定ファイル.これまたお好みで.

インストールスクリプトを実行.

% sudo ./build-lighttpd.sh

他のマシンから http://<ubuntuのIPアドレス>:10080/~<yourname>/HTML/ をアクセス.以下はサンプル.

f:id:ihag:20080412190325p:image

または,mozilla.orgが提供しているLXRも便利かも.

そのほか

インストール手順は,とりあえずshell scriptで書いておいて,SVNレポジトリに放り込んでおくと便利.新しいマシンをセットアップしたら,レポジトリの内容をtarアーカイブにしてSFTPして実行,という具合にすれば楽.

Connection: close