コグノスケ


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

link もっと前
2015年3月7日 >>> 2015年2月22日
link もっと後

2015年3月7日

ファミコンのCPU

昨日の飲み会でファミコンのCPUがZ80だって大嘘ついてしまった……。

正解はMOS 6502(の互換CPU、リコー製)です。

覚えていたら月曜に訂正しておこう。

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

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

コメント一覧

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



2015年3月6日

SysV initの処理変更(直列版)

目次: Linux

昨日(2015年3月5日の日記参照)に引き続き、何となく自分ではわかっているつもりでしたが、いざ変更しようとしたら全然わかっていなかったSysV initの話です。

まずはSysV initの動きのおさらいから。

おさらい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に起動を任せる

さて、お忘れの方も多いかと思いますが、本題は「initの処理に何か足したい」でした。

もしCONCURRENCY=noneつまり直列版のinitを使っている場合、initに何か足す方法は非常に簡単です。今まで見てきたように、/etc/rcS.d以下にスクリプトファイルを足せば、/etc/init.d/rcSが実行してくれます。

SysV initの処理変更(並列版)

しかしCONCURRENCY=makefileつまり並列版のinitを使っている場合、/etc/rcS.d以下にスクリプトファイルを足すだけでは実行されません。なぜかというとstartparというコマンドが一枚噛んでいるためです。

このstartparというコマンドには2つのモードがあります。

man startparより
NAME
       startpar - start runlevel scripts in parallel

SYNOPSIS
       startpar [-p par] [-i iorate] [-t timeout] [-T global_timeout] [-a arg]
       prg1 prg2 ... ★1
       startpar [-p par] [-i iorate] [-t timeout]  [-T  global_timeout]  -M  [
       boot|start|stop] ★2

一つは ★1側の、渡された引数を実行するCONCURRENCY=noneに近い動作をするモード(引数に -Mを指定しない)です。
もう一つは ★2側の、別の設定ファイルからスクリプトの依存関係を得て、出来る限り並列に実行する(引数に -Mを指定する)モードです。

さて /etc/init.d/rcでは、startparの2つモードのうち、どちらが使われていたでしょうか?覚えている人はスゴい暗記力です。私も含めて忘れてしまった方のために、もう一度コードを見ます。

/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

簡単ですね。別の設定ファイルを見る(-Mを指定する)モードです。しかもよく見るとstartup() に渡されているスクリプト名($2以降の引数)は無視されています。だから /etc/rcS.d/ にスクリプトを足すだけでは、実行されなかったのです。

startparの設定ファイル更新

ではstartparに何か処理を追加するには、何をどうしたら良いのか?と言う話です。こういうときはまずstartparのマニュアルを見てみます。

man startparより
       The -M option switches startpar into a make(1)  like  behaviour.   This
       option takes three different arguments: boot, start, and stop for read-
       ing .depend.boot or .depend.start or .depend.stop respectively  in  the★1
       directory  /etc/init.d/.  By scanning the boot and runlevel directories
       in /etc/init.d/ it then executes the appropriate scripts in parallel.

FILES
       /etc/init.d/.depend.boot
       /etc/init.d/.depend.start
       /etc/init.d/.depend.stop

SEE ALSO
       init(8) insserv(8). ★2

★1の説明を見るに、-Mはboot, start, stopのうちどれか1つ引数を取って、実際の動作は .depend.boot or .depend.start or .depend.stopで決まりますよ、というようなことが書いてあります。親切なことにFILESの章にファイルのフルパスまで書いてくれています。

これら3つの .depend.XXXXファイルを更新すれば良い、ということがわかりましたが、どうやって更新するのかが書いていなくて困ってしまいます。とりあえず★2のSEE ALSOの章にあるinsservという奴が新顔で怪しいので、マニュアルを見ます。

man insservより
INSSERV(8)                                                          INSSERV(8)

NAME
       insserv  -  boot  sequence organizer using LSB init.d script dependency
       information

(...略...)

FILES
       /etc/insserv.conf
              configuration file for insserv  which  defines  the  LSB  System
              Facilities.

(...略...)

       /etc/init.d/.depend.boot,
       /etc/init.d/.depend.start,
       /etc/init.d/.depend.stop
              The make(1) like dependency files produced by insserv for  boot‐
              ing, starting, and stopping with the help of startpar(8). ★1

コマンドの説明はちょっと抽象的でわかりづらいですが、FILESの ★1の部分を見る限り、探し求めていた物に間違いないでしょう。

SysV initの処理変更の仕方、まとめ
1. /etc/rcS.d/ にS20script.shのような名前のスクリプトを追加する

2. startpar -Mを使っている場合は、insservを実行して設定ファイルを更新する

まとめてしまえば短いものですが、これもinitの仕組みの一端だと思うと、中々に感慨深いもんがありますね。

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

コメント一覧

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



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 この記事にコメントする



link もっと前
2015年3月7日 >>> 2015年2月22日
link もっと後

管理用メニュー

link 記事を新規作成

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

最近のコメント20件

  • link 21年9月20日
    すずきさん (11/19 01:04)
    「It was my pleasure.」
  • link 21年9月20日
    whtさん (11/17 23:41)
    「This blog solves my ...」
  • link 24年10月1日
    すずきさん (10/06 03:41)
    「xrdpで十分動作しているので、Wayl...」
  • link 24年10月1日
    hdkさん (10/03 19:05)
    「GNOMEをお使いでしたら今はWayla...」
  • link 24年10月1日
    すずきさん (10/03 10:12)
    「私は逆にVNCサーバーに繋ぐ使い方をした...」
  • link 24年10月1日
    hdkさん (10/03 08:30)
    「おー、面白いですね。xrdpはすでに立ち...」
  • link 14年6月13日
    2048player...さん (09/26 01:04)
    「最後に、この式を出すのに紙4枚(A4)も...」
  • link 14年6月13日
    2048playerさん (09/26 01:00)
    「今のところ最も簡略化した式です。\n--...」
  • link 14年6月13日
    2048playerさん (09/16 01:00)
    「返信ありがとうございます。\nコメントが...」
  • link 14年6月13日
    すずきさん (09/12 21:19)
    「コメントありがとうございます。同じ結果に...」
  • link 14年6月13日
    2048playerさん (09/08 17:30)
    「私も2048の最高スコアを求めたのですが...」
  • link 14年6月13日
    2048さん (09/08 17:16)
    「私も2048の最高スコアを求めたのですが...」
  • link 14年6月13日
    2048playerさん (09/08 16:10)
    「私も2048の最高スコアを求めたのですが...」
  • link 02年8月4日
    lxbfYeaaさん (07/12 10:11)
    「555」
  • link 24年6月17日
    すずきさん (06/23 00:12)
    「ありがとうございます。バルコニーではない...」
  • link 24年6月17日
    hdkさん (06/22 22:08)
    「GPSの最初の同期を取る時は見晴らしのい...」
  • link 24年5月16日
    すずきさん (05/21 11:41)
    「あー、確かにdpkg-reconfigu...」
  • link 24年5月16日
    hdkさん (05/21 08:55)
    「システム全体のlocale設定はDebi...」
  • link 24年5月17日
    すずきさん (05/20 13:16)
    「そうですねえ、普通はStandardなの...」
  • link 24年5月17日
    hdkさん (05/19 07:45)
    「なるほど、そういうことなんですね。Exc...」

最近の記事3件

  • link 23年4月10日
    すずき (11/15 23:48)
    「[Linux - まとめリンク] 目次: Linux関係の深いまとめリンク。目次: RISC-V目次: ROCK64/ROCK...」
  • link 24年11月6日
    すずき (11/15 23:47)
    「[Ubuntu 24.04 LTS on ThinkPad X1 Carbon Gen 12] 目次: Linux会社ではTh...」
  • link 24年11月11日
    すずき (11/15 23:26)
    「[Pythonのテストフレームワーク] 目次: Python最近Pythonを触ることが増えたのでテストについて調べようと思い...」
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

最終更新: 11/19 01:04