chkconfigの使い方

chkconfigは/etc/init.dに登録されたサービスの自動起動を管理するコマンド。
なんどやっても覚えないのでまとめとく。

サービスの一覧

登録されているサービスを表示するには--listを指定する。(と言っても省略可)
サービス毎にどのランレベルで起動するかを示している。

$ chkconfig --list  # もしくはchkconfig
NetworkManager  0:off   1:off   2:on    3:on    4:on    5:on    6:off
abrtd           0:off   1:off   2:off   3:on    4:off   5:on    6:off
atd             0:off   1:off   2:off   3:on    4:on    5:on    6:off
auditd          0:off   1:off   2:on    3:on    4:on    5:on    6:off
avahi-daemon    0:off   1:off   2:off   3:on    4:on    5:on    6:off
bluetooth       0:off   1:off   2:off   3:on    4:on    5:on    6:off
cpuspeed        0:off   1:on    2:on    3:on    4:on    5:on    6:off
…

サービス名を指定すれば、そのサービスだけ表示できる。(この場合--listは必須)

$ chkconfig --list crond
crond               0:off     1:off     2:on     3:on     4:on     5:on     6:off

サービスの自動起動を変更

sshdサービスの自動起動をON

# chkconfig sshd on

レベルを指定してONにする場合は

# chkconfig --level 35 sshd on  # ランレベルが3か5の場合に起動する

sshdサービスの自動起動をOFF

# chkconfig sshd off

サービスの追加・削除

パッケージを利用してると、大抵は追加されているので実行したことないけど
自動起動するサービスを追加・削除できる。

sshdサービスを追加

# chkconfig --add sshd

sshdサービスを削除

# chkconfig --del sshd

ちなみに

ランレベル毎にサービスを起動するかどうかは、/etc/rc(ランレベル).d/以下のシンボリックリンクで決まる。

$ ls -l /etc/rc*.d/*crond
lrwxrwxrwx. 1 root root 15 2010-04-20 02:08 /etc/rc0.d/K60crond -> ../init.d/crond*
lrwxrwxrwx. 1 root root 15 2010-04-20 02:08 /etc/rc1.d/K60crond -> ../init.d/crond*
lrwxrwxrwx. 1 root root 15 2010-04-20 02:08 /etc/rc2.d/S90crond -> ../init.d/crond*
lrwxrwxrwx. 1 root root 15 2010-04-20 02:08 /etc/rc3.d/S90crond -> ../init.d/crond*
lrwxrwxrwx. 1 root root 15 2010-04-20 02:08 /etc/rc4.d/S90crond -> ../init.d/crond*
lrwxrwxrwx. 1 root root 15 2010-04-20 02:08 /etc/rc5.d/S90crond -> ../init.d/crond*
lrwxrwxrwx. 1 root root 15 2010-04-20 02:08 /etc/rc6.d/K60crond -> ../init.d/crond*

chkconfigはこのシンボリックリンクを編集しているようだ。
Kで始まるシンボリックリンクがOFFで、Sで始まるのがONってことね。

Snow LeopardにしたらMacPortsが動かなくなった

Snow Leopardにしてからportコマンドエラーが出るようになった。

dlopen(/Library/Tcl/macports1.0/MacPorts.dylib, 10): no suitable image found.  Did find:
     /Library/Tcl/macports1.0/MacPorts.dylib: mach-o, but wrong architecture
    while executing
"load /Library/Tcl/macports1.0/MacPorts.dylib"
    ("package ifneeded macports 1.0" script)
    invoked from within
"package require macports"
    (file "/opt/local/bin/port" line 39)

もともとMacPortsは、単一のOS・CPUで動作するように設計されており、OSやCPUが変わると再インストールが必要なようだ。

http://trac.macports.org/wiki/Migrationに移行方法が書かれていたので実践してみる。

Portsを再インストール

まずはSnow Leopard版のXcodeが必要なのでインストールディスクからインストールしておく。
次にSnow Leopard版のMacPortshttp://www.macports.org/install.php
から最新のdmgをダウンロードし、インストールし直す。 (現時点で最新は1.9.2)


続いてインストール済みリストを書き出す。

$ port installed > myports.txt

インストール済みのポートをすべてアンインストール。

$ sudo port -f uninstall installed

ビルドやアーカイブを削除。

$ sudo port clean --work --archive all

最後に、myports.txを見ながら適切なvariantを設定しつつ、1つずつインストールする。

$ sudo port install portname +variant1 +variant2 ...

1つずつインストールする…。
…。
いやいや、めんどくさい。
201個もあるんだよ、ムリムリ。

自動再インストール

幸い実験的ではあるけど、自動インストールスクリプトrestore_ports.tclが用意されている。
次のコマンドでダウンロード・実行可能にする。

$ curl -O http://svn.macports.org/repository/macports/contrib/restore_ports/restore_ports.tcl
$ chmod +x restore_ports.tcl

以前にインストールしていたポートのリスト(myports.txt)を指定して実行。

$ sudo ./restore_ports.tcl myports.txt

そのままでは恐らく次のようなエラーが出るので

couldn't read file "/Library/Tcl/macports1.0/macports_fastload.tcl": no such file or directory
    while executing
"source ${macportsTclPath}/macports1.0/macports_fastload.tcl"
    (file "./restore_ports.tcl" line 244)

-tでtclのパスを指定してあげる。

$ sudo ./restore_ports.tcl -t /opt/local/share/macports/Tcl myports.txt

あとは自動的にイントールしてくれるので、基本的には待つだけ。

エラーがでた場合

依存関係によっては、ポートをdeactivateできなくてエラーがでることも。

--->  Deactivating p5-compress-raw-zlib
--->  Unable to uninstall/deactivate p5-compress-raw-zlib @2.027_0, the following ports depend on it:
--->       p5-io-compress @2.027_0
port deactivate failed: Please uninstall the ports that depend on p5-compress-raw-zlib first.
    while executing
"install_ports $operationList"
    (file "./restore_ports.tcl" line 264)

この場合は、dependentsで依存しているポートを調べて

$ port dependents p5-compress-raw-zlib

uninstallしてみる。

$ sudo port uninstall p5-io-compress

再度、restore_ports.tclを実行すればOK。

終わりに

restore_ports.tclは一気にインストールするため、かなりの時間がかかる。
再インストールのリスト(myports.txt)は実行前に整理して、不要なポートは削っておくといいと思う。
ただ、ここまで書いといてなんだけど、かなりの確立でエラーが発生するので
ポートの数が少ないなら個別にインストールしたほうが簡単かもしれない。

.ssh/configでサーバを踏み台にする方法

はじめに

ログインしたいサーバが直接公開されておらず、別のサーバを経由しないとログインできないことがある。
そんな時はProxyCommandが便利。

やり方

~/.ssh/configに次のように記述してみよう。

Host honmei-host
  ProxyCommand ssh fumidai-host nc %h %p
  HostName 192.168.11.7

honmei-hostが最終的に接続したいホスト。
ProxyCommandのfumidai-hostには経由したいホストを指定する。
HostNameには、fumidai-hostから見えるhonmei-hostへのIPアドレスを指定する。ポートを指定する場合も同様に。

※ただし、fumidai-hostにはncコマンドが必要。大抵入ってるみたいだけど。


後はいつも通りhonmei-hostにアクセス。

ssh honmei-host

すると、まずfumidai-hostへのパスワードを、続いてhonmei-hostへのパスワードを訊かれるようになる。
それぞれ認証が通れば無事ログインできるよ。

vimshellが便利過ぎる件

vimshellとは?

vimshellはVimからシェルを起動するVimScript。
ただ起動するだけなら:!コマンドでも足りるけど、こちらは非同期に処理できないので、実行中はVimでコードを書けないとか欠点が多い。
vimshellなら非同期なシェルが使えるし、色分け・補完もきく。
インタプリタを立ち上げれば、コードを書きつつ評価させることもできるよ、Emacsみたいにね!

インストール

http://github.com/Shougo/vimshell からソースをダウンロード。
解凍したファイルを~/.vim以下に保存。

あと同作者さんのvimprocが必要なので
https://github.com/Shougo/vimproc からソースをダウンロード。

こちらは~/.vim以下に保存するだけではダメで、Linuxではコンパイルする必要がある。

Linuxでは、次のコマンドを実行。

make -f make_gcc.mak

コンパイルが通ったら、autoload/にあるファイルやディレクトリを~/.vimのautoloadディ
レクトリにコピーする。たぶん、proc.so・vimproc.vim・vimproc/だけ保存すればいいと思う。

Vimからシェルを起動する

シェルを起動するには、次のコマンドを実行するだけ、簡単。

:VimShell

シェル上では挿入モードでコマンド実行できる。
lsとかcdとか一般的なコマンドは普通に使える。(なんかたまに警告でるけど)

あと、pythonのようなインタプリタはそのままでは起動できないようだ。
実行するには、直接インタプリタを呼ばずiexeをかますせばOK。

iexe python

インタプリタを起動して対話的にコードを評価させる (Emacsみたいに)

単純にシェルを実行するだけなら:VimShellで十分。
でも別ウィンドウで書いたコードをシェルに評価させる場合は、:VimShellInteractiveを使う。
引数に起動したいインタプリタを指定しよう。

:VimShellInteractive python

すると、左がインタプリタで、右がコードを書くウィンドウが表示される。
で挿入モードを抜けて、lで右のウィンドウへ。

では右のウィンドウでコードを書いてみよう。
書き上がったら、選択してから次のコマンドを実行。

:VimShellSendString

すると、左のインタプリタに選択してたコードが渡り評価されるよ。

こんな感じで、ちょこちょこコードを書いては評価してを繰り返すことができる。
ワンライナーで書けないコードを試すには最高だね♪

最後に

毎回コマンドを入力するのは面倒なので、~/.vimrcにショートカットを登録しておくべし。

" ,is: シェルを起動
nnoremap <silent> ,is :VimShell<CR>
" ,ipy: pythonを非同期で起動
nnoremap <silent> ,ipy :VimShellInteractive python<CR>
" ,irb: irbを非同期で起動
nnoremap <silent> ,irb :VimShellInteractive irb<CR>
" ,ss: 非同期で開いたインタプリタに現在の行を評価させる
vmap <silent> ,ss :VimShellSendString<CR>
" 選択中に,ss: 非同期で開いたインタプリタに選択行を評価させる
nnoremap <silent> ,ss <S-v>:VimShellSendString<CR>

いやぁ、もうvimshell最高♪

SQLAlchemyでカラムの値を遅延ロードする方法

どんなO/Rマッパでもそうだと思うけど、モデルを取得すると基本的に全てのカラムから値を取り出そうとする。
1レコードのサイズが少なければ問題にならないが、BLOBのようにサイズの大きなカラムを追加するととたんにパフォーマンスが悪くなってしまう。
SQLAlchemyもそのあたりは同じ。
でもどのカラムが必要で不要なのか細かく指示できるので、うまく調節すれば取り出す値を最小限にとどめることができる。

適用例

userテーブルはBLOB型のiconカラムを持っている。

# テーブル定義
user_table = sqlalchemy.Table(
    'user', meta_data,
    sqlalchemy.Column('id',   sqlalchemy.Integer, sqlalchemy.Sequence('user_id_seq'), primary_key = True),
    sqlalchemy.Column('name', sqlalchemy.Unicode(32), nullable = False),
    sqlalchemy.Column('icon', sqlalchemy.BLOB, nullable = False))

# マッピング定義
sqlalchemy.orm.mapper(User, user_table,
    properties = {
        # ここのdeferred()で遅延ロードを指定している
        'icon': sqlalchemy.orm.deferred(user_table.c.icon)
    })

deferred()を利用することで、iconプロパティは参照されるまでロードしなくなる。

users = db_session.query(User).all()  # id、nameはロードされるがiconはロードされない

for user in users:
    user.id      # idはすでにロードされている
    user.icon  # ここでようやくiconをロード

実行されるSQLの比較

deferredなし

SELECT "user".id AS user_id, "user".name AS user_name, "user".icon AS user_icon
FROM "user"

当たり前だけどiconをロードしてる。

deferredあり

SELECT "user".id AS user_id, "user".name AS user_name
FROM "user"

おぉ、ちゃんとiconだけ除外されてる!

問い合わせ時に遅延するか決める

iconのデータも利用することが分かっているのなら、遅延させずに取ってきたいこともある。
そんな時はQuery.options()を使おう。
undefer()を設定すれば、その問い合わせに限り遅延しなくなる。

from sqlalchemy.orm import undefer
query = query.options(undefer('icon'))

逆に普段は遅延しない(deferred()なし)のに、今回だけ遅延させたい場合はdefer()を設定する。

from sqlalchemy.orm import defer
query = query.options(defer('icon'))

まとめ

O/RマッパはSQLを隠蔽できて便利な反面、どんなSQLが実行されるのか意識しづらい。
知らないうちに非効率なSQLになっていることがあるので注意が必要だ。
幸いSQLAlchemyには、deferred以外にもいろいろチューニングできそうなのでもっと調べていきたい。

というわけで、BLOBのようにサイズの大きなカラムはdeferredしましょう、というお話でした。

参考: http://www.sqlalchemy.org/docs/05/reference/orm/mapping.html#sqlalchemy.orm.deferred

Gitのリポジトリからファイルをエクスポート

svn exportみたいに、ファイルをエクスポートする機能を見つけたのでメモメモ。

例:

$ git checkout-index -a -f --prefix=export/
  • -a
    • 履歴管理されているすべてのファイルをエクスポート。省略した場合は明示的にファイルを指定する
    • 例) $ git checkout-index -prefix=export/ ファイル1 ファイル2 ...
  • -f
    • エクスポート先に同名のファイルが存在する場合は上書きする
  • --prefix
    • エクスポート先

--prefixを指定する場合は、末尾に'/'を付けないと悲惨なことになるので要注意。
次のコマンドの場合

$ git checkout-index --prefix=.merged- Makefile

.merged-/Makefileではなく、.merged-Makefileという名前でエクスポートしてしまう。


最初もろに引っ掛かってびっくりしたw。
あまりこの動作を期待することって少ないと思うけど、需要があるってことなのかなぁ。

MacのDNSを設定

ハマったのでメモメモ。
Macに自前のDNSを設定しようと、/etc/resolv.confにnameserverを追加してみた。

nameserver 172.16.232.131

でも一向に反映されない。digで調べても以前のDNSに問い合わせている。
ネットで調べたところ、Macのresolv.confは仮初めのもので、内部で管理している結果をはき出しているだけみたい。

で、本当に設定するには、「システム環境設定」->「ネットワーク」を開き

DNSサーバの欄に、IPアドレスをカンマ区切りで入れて「適用」を押せばOK。
えらい簡単だ♪


以下は、DNS関連のちょっとしたTips。

特定のドメインだけDNSを切り替える方法

参考:MacOS X でドメイン毎にDNSサーバを切り替える | 胡桃ヶ谷

Macの/etc/resolver以下に、DNSを変更したいドメインと同名のファイルを作成する。
(/etc/resolverディレクトリが存在しない場合は作成する)
中の書式はresolv.confと同じで、問い合わせたいDNSを指定できる。

# mkdir /etc/resolver/
# echo nameserver 192.168.1.1 > /etc/resolver/localnet.intra

この場合、localnet.intraにアクセスすると192.168.1.1のDNSに問い合わせるようになるよ。

DNSのキャッシュをクリアする

参考:試験管のなかのコード :: Mac OS X で DNS キャッシュのクリア

DNSの問い合わせ結果は内部でキャッシュされるため、変更してもすぐに反映されないことがある。
Leopard以降は、次のコマンドでキャッシュをクリアできる。

$ dscacheutil -flushcache