不完全なデーモンプロセスに制御端末を割り当てる方法を教えてください


UNIX のデーモンプロセスについて勉強しています。デーモンプロセスを作るには、

1. fork する (子プロセスを作って親は死ぬ)
2. setsid する (子プロセスを制御端末から切り離す)
3. もう一度 fork する (セッションリーダーではない孫プロセスを作って子は死ぬ)

という手順を踏むのだと、後述のブログ記事等で知りました (chdir, umask, STDIN/STDOUT/STDERR などの取り扱いは、今回は注目しないので省略します)

この 3. でやっている二度目の fork が必要な根拠として、セッションリーダーであるデーモンプロセス (1. で fork した子プロセス) に制御端末を割り当てられてしまうとまずいためだ、という理由が挙げられています (シグナルを送られてプロセスを操られてしまうとか)。まずいケースを実体験したいのでそのようなプロセスに制御端末を割り当ててみたいのですが、やり方がわかりませんので教えてください。

https://github.com/kyanny/sample-daemon に Ruby で書いたサンプルプログラムがありますのでこちらもあわせてご覧ください。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2011/11/03 01:40:23
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:TransFreeBSD No.1

回答回数668ベストアンサー獲得回数268

ポイント500pt

FreeBSDで確認しました。linuxだとioctlがいらないかもしれません。

pythonが一番楽なのでまずはpythonで。

#!/usr/local/bin/python
import os, pty, sys, time, fcntl, termios

if os.fork() <> 0:
    sys.exit()
os.setsid()
master, fd = pty.openpty()
#fd = os.open('/dev/ttyv9', os.O_RDWR)
fcntl.ioctl(fd, termios.TIOCSCTTY, 0)
while True:
    time.sleep(1)

擬似端末を取得して割り当てます。

既にプロセスに割り当てられている端末は別プロセスに割り当てが出来ませんので、未使用の端末か擬似端末を使用します。

linux及びBSD系では openpty(3) により擬似端末を取得できます。

SYSV系及びlinuxでは 端末が未割り当てのセッションリーダーが端末を開くと自動的に割り当てられるとのことですが、環境がないので確かめていません。

もし open(2) または openpty(3) の時点で端末割り当てが行われているなら、次の ioctl(2) は失敗すると思いますので、コメントアウトしてください。

BSD系では ioctl(2) のTIOCSCTTYにより明示的に割り当てます。

二度目のforkの後では失敗することも確認しました。

なお、コメントアウトしてありますが、擬似端末ではなく実際の端末を開いてもOKですが、パーミッション上rootでなければならないと思います。確かめる際はopenで開く端末を未使用の存在する端末に変更してください。

perl, rubyは openpty(3) がないのと、TIOCSCTTYが定義されていないようなので通常の端末を開いて、ioctlは数字指定で行いました。参考に書きますが適宜環境に合わせて変更してください。

#!/usr/bin/env ruby

exit if fork
Process.setsid
open('/dev/ttyv9', File::RDWR){|f|
    f.ioctl(0x20007461)
    sleep 1 while true
}

#!/usr/local/bin/perl
use strict;
use warnings;
use POSIX;

exit if (fork != 0);
setsid or die $!;
sysopen(HANDLE, '/dev/ttyv9', O_RDWR) or die $!;
ioctl(HANDLE, 0x20007461, 0) or die $!;
sleep(1) while (1);
id:a666666

ありがとうございます! Python のコードを Linux で動かして、端末が割り当てられることを確認できました。どういう理屈なのかまで含めて説明してもらって、とてもよくわかりました。 openpty や TIOCSCTTY などのポインタも示していただけたので、さらに自分でも調べてみようと思います。

2011/11/03 01:40:17
  • id:TransFreeBSD
    制御端末をデーモンが自主的に割り当てるコードでよいのでしょうか?
    外部操作により割り当てられてしまうとか、制御端末を持つことで操られるとかまでは必要ない、と言う認識であってますか?
    あと、環境はやっぱりlinuxですか?
    OS依存が若干気になります。
  • id:a666666
    > 制御端末をデーモンが自主的に割り当てるコード
    これで結構です。Perl, Ruby, Python あたりのコード例だと嬉しいです。

    > 環境はやっぱりlinuxですか?
    自分が試したのは Linux ですが他のプラットフォーム用のコードでもかまいません。その場合、なぜ Linux では動かないのかも教えていただけると嬉しいです。
  • id:a-kuma3
    # もたもたしている間に、解決しちまったい =)

    C 言語ですけど、疑似端末を割り当てるときのコードが書いてあるページ。
    http://book.chinaunix.net/special/ebook/addisonWesley/APUE2/0201433079/ch19lev1sec3.html

    ここの STREAMS-Based では、ptsname() って関数を自前で用意しているけど、
    POSIX では ptsname() はライブラリで提供されるはず。

    後、プロセスグループだの、セッションリーダだの、っていうのを理解するときに役に立ちそうな所。
    http://pinka99.ddo.jp/nanao/work/daemon.html
    http://www.glamenv-septzen.net/view/854

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません