コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2015年3月5日 >>> 2015年2月20日
link もっと後

2015年3月5日

SysV initの仕組みと変更を反映する方法

目次: Linux

何となく自分ではわかっているつもりでしたが、いざ変更しようとしたら全然わかっていなかった initの話です。

突然ですがLinuxマシンのブート時にやりたいことが増えた場合、どうやって変えたら良いでしょうか?SysV initなら /etc/inittabか /etc/init.d/rcSを変えれば?とサラりと答えられる方は、きっとかなり詳しい方ですね。

せっかく書くので、初めて見る人でもわかるように……とまでは言いませんが、Linuxのブート時には何が実行されるのか?を1つずつ見ていこうと思います。

init以前

Linuxカーネルは起動が終わると、PID 1のプロセスとして、下記リストを上から順に実行しようとします(参考: linux/init/main.cのkernel_init() 関数)。

  • カーネルの引数init= に指定したパス
  • /sbin/init
  • /etc/init
  • /bin/init
  • /bin/sh

通常の利用ではinit= を指定しないと思いますので、/sbin/initが実行されるはずです。Debianでは(※)これがSystem V initを指しています。

(※)Debianに限らず昔はSysV initが多かったのですが、最近はUbuntuのupstart、Gentoo Linuxのopenrc、Fedora Coreのsystemdのように、SysV init以外のinitも増えています。設定の方法が皆違うので、同時に使うと混乱します……。

initとinittab

SysV initは /etc/inittabという設定ファイルに従って動作します。このinittabというファイルにはrunlevelがいくつのときは、こういう動作をしなさい、という命令が羅列されています。

ちなみにrunlevelとはSysV initの動作モードのことで、大抵は0〜6, Sの8つのモードがあります。実際に使われるのは3〜4個(0: マシン停止、1: シングルユーザ、2や3: デフォルト、6: マシン再起動)だったりしますけど。デフォルトのrunlevelはディストリビューションによって違います。たぶん2が多いんじゃないかな。

例としてDebian GNU/Linux 7.8(Wheezy) の /etc/inittabを見てみます。

/etc/inittabの一部抜粋

# The default runlevel.
id:2:initdefault: ★デフォルトのrunlevel★

# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS★runlevelに無関係に、システムブート中に実行される。★

(...略...)

l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2★runlevel 2なら、ここが実行される★
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6

(...略...)

Debianの場合、まず最初に /etc/init.d/rcSが実行され、その後、デフォルトrunlevelの2に対応する /etc/init.d/rc 2が実行される、ということがわかります。ちなみに /etc/init.d/rcSは、下記のような実装です。

/etc/init.d/rcS

#! /bin/sh
#
# rcS
#
# Call all S??* scripts in /etc/rcS.d/ in numerical/alphabetical order
#

exec /etc/init.d/rc S

すなわち、initは/etc/init.d/rc Sと /etc/init.d/rc 2を実行しているだけです。ここまでの話をまとめておくと、

おさらい1
前提: ディストリビューションはDebian GNU/Linux 7.8(Wheezy) 

1. Linux Kernel起動終盤にkernel_init() が /sbin/initを起動

2. /sbin/initは /etc/inittabを見る

3. /etc/inittabにはinitへの指示が書いてある
  3-1. デフォルトのrunlevelは2である
  3-2. ブート時に /etc/init.d/rcSを実行せよ
    3-2-1. /etc/init.d/rcSは /etc/init.d/rc Sを起動する
  3-3. runlevel 2なら /etc/init.d/rc 2を実行せよ

こうなります。割とシンプルですよね。

/etc/init.d/rc

簡単に言えば/etc/rcXXXX.dディレクトリの中に入っている初期化スクリプトを全部実行するランチャーです。XXXXの部分にはrcの第一引数に指定したrunlevelが入ります。例えばrc Sであれば /etc/rcS.d/* が、rc 2であれば /etc/rc2.d/* が実行されます。

スクリプトの先頭から中程にかけて色々と環境変数を設定していますが、注目すべきは、CONCURRENCYという変数です。rcはこのCONCURRENCYという変数の値によって大きく動作が変わります。

/etc/init.d/rcの一部抜粋、CONCURRENCYの定義

#
# Check if we are able to use make like booting.  It require the
# insserv package to be enabled. Boot concurrency also requires
# startpar to be installed.
#
CONCURRENCY=makefile
test -s /etc/init.d/.depend.boot  || CONCURRENCY="none"
test -s /etc/init.d/.depend.start || CONCURRENCY="none"
test -s /etc/init.d/.depend.stop  || CONCURRENCY="none"
if test -e /etc/init.d/.legacy-bootordering ; then
        CONCURRENCY="none"
fi
if ! test -e /proc/stat; then
        if [ "$(uname)" = "GNU/kFreeBSD" ] ; then
                # startpar requires /proc/stat
                mount -t linprocfs linprocfs /proc
        fi
fi
startpar -v > /dev/null 2>&1 || CONCURRENCY="none"

条件を洗っていくと、下記のいずれかが成立するときCONCURRENCY=noneとなり、いずれも成立しなければCONCURRENCY=makefileとなることがわかります。

  • /etc/init.d/.depend.bootが存在しないか、空ファイル
  • /etc/init.d/.depend.startが存在しないか、空ファイル
  • /etc/init.d/.depend.stopが存在しないか、空ファイル
  • /etc/init.d/.legacy-bootorderingが存在する
  • startpar -vコマンドが失敗する

次にCONCURRENCYの役割について調べるため、rcXXXX.d内のスクリプトを実行するためのstartup() という関数を見てみます。

/etc/init.d/rcの一部抜粋、startup() の定義

#
# Start script or program.
#
case "$CONCURRENCY" in
        makefile|startpar|shell) # startpar and shell are obsolete
                CONCURRENCY=makefile
                log_action_msg "Using makefile-style concurrent boot in runlevel
 $runlevel"
                startup() {
                        eval "$(startpar -p 4 -t 20 -T 3 -M $1 -P $previous -R $
runlevel)" ★1

(略)

        none|*)
                startup() {
                        action=$1
                        shift
                        scripts="$@"
                        for script in $scripts ; do
                                $debug "$script" $action★2
                        done
                }
                ;;

色々書いてありますが、簡単に言うと
CONCURRENCY=makefileであれば、startparを起動(★1)し、
CONCURRENCY=noneであればstartup() に渡された引数を一つずつ起動する(★2)、という作りです。

次に呼び出し側も見てみます。

/etc/init.d/rcの一部抜粋、startup() の呼び出し部分

# Now run the START scripts for this runlevel.
# Run all scripts with the same level in parallel
CURLEVEL=""
for s in /etc/rc$runlevel.d/S* ★1
do
        # Extract order value from symlink
        level=${s#/etc/rc$runlevel.d/S}
        level=${level%%[a-zA-Z]*}
        if [ "$level" = "$CURLEVEL" ]
        then
                continue
        fi
        CURLEVEL=$level
        SCRIPTS=""
        for i in /etc/rc$runlevel.d/S$level* ★2
        do
                [ ! -f $i ] && continue
                
                (...略...)

                SCRIPTS="$SCRIPTS $i" ★3
        done
        startup $ACTION $SCRIPTS★4
done

まず ★1にある * のパターン展開一発で、起動するべきスクリプトが「起動順に列挙」されます。

理由は2つで、/etc/rcS.d中のファイルは全て「S + 2桁の数字 + 名前.sh」という規則でファイル名が付けられていること、なおかつ、bashは * の展開結果をアルファベット順にソートする仕様(下記を参照)だからです。

man bashより
   パス名展開
       -fオプションが指定されていなければ、単語分割を行った後にbashはそれぞ
       れの単語が *, ?, [ を含んでいるかどうか調べます。  これらの文字のいずれ
       かが見つかると、その単語は  パターン  とみなされ、 パターンにマッチする
       ファイル名を アルファベット順にソートしたリストに置換されます。  マッチ
       ...

次に ★2から ★3の間の処理で、同じレベルのスクリプト名を列挙して全て連結し、★4でstartup() にスクリプト名を渡して実行します。ちなみにrunlevel Sおよび2のときのACTION変数には "start" が入っています。

例えばS10zzz.sh S20aaa.shとS20bbb.shとS30ccc.shがあったとしますと、

  • startup start S10zzz.sh
  • startup start S20aaa.sh S20bbb.sh
  • startup start S30ccc.sh

このような順にstartup() が呼ばれることになります。

おさらい2
前提: ディストリビューションはDebian GNU/Linux 7.8(Wheezy) 

1. Linux Kernel起動終盤にkernel_init() が /sbin/initを起動

2. /sbin/initは /etc/inittabを見る

3. /etc/inittabにはinitへの指示が書いてある
  3-1. デフォルトのrunlevelは2である
  3-2. ブート時に /etc/init.d/rcSを実行せよ
    3-2-1. /etc/init.d/rcSは /etc/init.d/rc Sを起動する
  3-3. runlevel 2なら /etc/init.d/rc 2を実行せよ

↑↑↑↑↑ 以上、おさらい1の部分 ↑↑↑↑↑

4. 下記がいずれか一つでも成立すればCONCURRENCY=none成立しなければCONCURRENCY=makefile
  - /etc/init.d/.depend.bootが存在しないか、空ファイル
  - /etc/init.d/.depend.startが存在しないか、空ファイル
  - /etc/init.d/.depend.stopが存在しないか、空ファイル
  - /etc/init.d/.legacy-bootorderingが存在する
  - startpar -vコマンドが失敗する

5. /etc/rcXXXX.d/S* をアルファベット順に実行
   CONCURRENCY=noneならば、単に実行するだけ、
   CONCURRENCY=makefileならば、startparに起動を任せる
編集者:すずき(2023/04/29 21:43)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2015年3月3日

Intelとモバイル端末

PC Watch - Intel、3G/LTE統合型SoC「Atom x3 C3000」シリーズを読んで。

個人的にはIntelのSoCは携帯端末向けと言いつつ、PCとしても使えます!という作りにした方が輝くと思いますが、その路線も、単純に攻めるのはもう限界とも思います。

というのもPCとして使おうとすると、どうしてもある程度の画面サイズ(出力手段)と、キーボード(入力手段)が欲しくなるからです。

Baytrailが8〜 インチタブレットを捉えたので、単純に考えれば次に狙うのは7インチ以下のタブレットですが、7インチの画面はPCとしては小さすぎますし、キーボードも端末の倍近いサイズになって非常に格好悪いです。

出力手段は、画面を折るとか重ねるとか何とかするにしても、入力手段だけはキーボード以外でキーボード以上の正確さと速さを持つものを見つけないと、ミニ画面PCを実現するのは、ちょいと厳しそうですね…。

メモ: 技術系の話はFacebookから転記しておくことにした。

編集者:すずき(2015/11/29 05:08)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2015年3月2日

自作ARMエミュレータ - アイドル処理

目次: Linux

自作ARMエミュレータのアイドル状態を実装して、何もしていないのにCPU時間をバカ食いしていた問題を解決しました。

ARM9コアをアイドル状態に移行させるには、mcr命令を使ってコプロセッサ15の特定のレジスタにストアします。具体的に言うとmcr 15, 0, r0, cr7, cr0, {4}(opcode_1:0, crn:7, rd:0, opcode_2:4, crm:0)です。ただ、これだけ実行すれば良いものでもないので、詳細はLinuxのarch/arm/mm/proc-arm926.Sのcpu_arm926_do_idleという関数が参考になります。

アイドル状態に入るとCPUは停止し、デバイスから割り込みが掛かると再開します。実装する前は簡単かなーと思っていたのですが、やってみると意外と大変でした。

今まで割り込み回りの実装をサボっていて、CPUからデバイスの割り込みステータスを全力でポーリングするだけのやっつけ処理しか実装しておらず、デバイスからCPUに何か通知する仕組みが全くなかったためです。

どう見ても自業自得ですね。うん。

編集者:すずき(2024/03/05 02:54)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2015年3月1日

プロフィール更新

新会社に転籍しましたのでプロフィール更新しました。新会社の発足日にも関わらず、公式サイトが未だにお葬式状態なのですが、どういうことなの…。

さよならパナソニック

2015年3月1日をもってソシオネクストに転籍しました。さよならパナソニック。

ソシオネクストは、富士通セミコンダクターとパナソニックのSLSI設計部門を合併させ、ファブレス(工場部門は既に分離済み)として再出発した会社です。

従業員は人事、経理などを除いてほぼ全員が転籍者です。出向と違い、元の会社に戻ることはありません。資本は富士通(4割)、パナソニック(2割)、日本政策投資銀行(4割)がソシオネクストに出資しています。

しかし、いずれの会社とも連結対象ではありませんので、赤字になっても救いの手はありません。反面、親会社の意向を気にせず自由に投資できます。たぶん…。

メモ: 技術系?の話はFacebookから転記(※)しておくことにした。

編集者:すずき(2015/03/02 01:33)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2015年2月22日

昔から使っているApacheの設定は危険

目次: 自宅サーバー

Twitterで知ったサイト ApacheのAddHandlerはセキュリティ上の懸念から使用すべきではない を読んでいたら、家に置いているサーバの設定に思い切り当てはまっていました。

このサイトにも .cgiファイルを使っている箇所があり、Apacheの設定ファイルには当然のごとくAddHandler cgi-script .cgiと書いてありました。

今のところ、任意のファイル名をアップロードする仕組みはなく、セキュリティホールにならなかったのが不幸中の幸いです。

教訓としては「昔から使っている設定だから動く」は成り立っても「昔から使っている設定だから安全」は成り立たない、ということですね。むしろ何も理解せずにコピペすると危険と言える良い例だったと思います。

編集者:すずき(2024/03/05 02:52)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2015年2月20日

なぜ胡散臭くなるのか

ソニー - ハイレゾ対応ウォークマン(R)に最適。高音質再生のためのメモリーカードを読んで。

せっかく輻射ノイズを測ったのなら、グラフの単位や、計測条件くらい書いてくれても良いのでは。

高級オーディオって、人を騙して高い物を売りつけるように見えたり、オカルトっぽく感じてしまうんですよねー。

メモ: 技術系の話はFacebookから転記しておくことにした。

編集者:すずき(2015/11/29 05:14)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2015年3月5日 >>> 2015年2月20日
link もっと後

管理用メニュー

link 記事を新規作成

<2015>
<<<03>>>
1234567
891011121314
15161718192021
22232425262728
293031----

最近のコメント5件

  • link 21年3月13日
    すずきさん (03/05 15:13)
    「あー、このプログラムがまずいんですね。ご...」
  • link 21年3月13日
    emkさん (03/05 12:44)
    「キャストでvolatileを外してアクセ...」
  • link 24年1月24日
    すずきさん (02/19 18:37)
    「簡単にできる方法はPowerShellの...」
  • link 24年1月24日
    KKKさん (02/19 02:30)
    「追伸です。\nネットで調べたらマイクロソ...」
  • link 24年1月24日
    KKKさん (02/19 02:25)
    「私もエラーで困ってます\n手動での回復パ...」

最近の記事3件

  • link 24年3月25日
    すずき (03/26 03:20)
    「[Might and Magic Book One TASのその後] 目次: Might and Magicファミコン版以前(...」
  • link 21年10月4日
    すずき (03/26 03:14)
    「[Might and Magicファミコン版 - まとめリンク] 目次: Might and Magicファミコン版TASに挑...」
  • link 24年3月19日
    すずき (03/20 02:52)
    「[モジュラージャックの規格] 古くは電話線で、今だとEthernetで良く見かけるモジュラージャックというコネクタとレセプタク...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 03/26 03:20