dd
debianの管理者ハンドブックを見てたら、lsXXXってのが有るのを知った。
sakae@debian:~$ ls ls lsblk lsinitramfs lsof lsusb lsattr lscpu lslocks lspci lsb_release lsdev lsmod lspgpot
魅せるなんとか軍団だな。
これは、diskの分割か。
sakae@debian:~$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 15G 0 disk ├─sda1 8:1 0 14.3G 0 part / ├─sda2 8:2 0 1K 0 part └─sda5 8:5 0 672M 0 part [SWAP] sr0 11:0 1 56.5M 0 rom
次は、PCIバスにぶら下がっているデバイス群。
sakae@debian:~$ lspci 00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02) 00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II] 00:01.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01) 00:02.0 VGA compatible controller: InnoTek Systemberatung GmbH VirtualBox Graphics Adapter 00:03.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 02) 00:04.0 System peripheral: InnoTek Systemberatung GmbH VirtualBox Guest Service 00:05.0 Multimedia audio controller: Intel Corporation 82801AA AC'97 Audio Controller (rev 01) 00:06.0 USB controller: Apple Inc. KeyLargo/Intrepid USB 00:07.0 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08) 00:0b.0 USB controller: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller 00:0d.0 SATA controller: Intel Corporation 82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [AHCI mode] (rev 02)
USBのハブは、リナ製とvbox製が付いているんだな。同じ事を、VMWAREでやったら、 どうなるんだろう。忘れずにやって見れ。
sakae@debian:~$ lsusb Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 002: ID 80ee:0021 VirtualBox USB Tablet Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
VMWARE上のfedora23では、こうなった。
[sakae@fedora ~]$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 12G 0 disk ├─sda1 8:1 0 500M 0 part /boot └─sda2 8:2 0 11.5G 0 part ├─fedora-root 253:0 0 10.3G 0 lvm / └─fedora-swap 253:1 0 1.2G 0 lvm [SWAP] sr0 11:0 1 1024M 0 rom
[sakae@fedora ~]$ lsusb Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub Bus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual Mouse Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
[sakae@fedora ~]$ lspci 00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01) 00:01.0 PCI bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge (rev 01) 00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 08) 00:07.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01) 00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08) 00:07.7 System peripheral: VMware Virtual Machine Communication Interface (rev 10) 00:0f.0 VGA compatible controller: VMware SVGA II Adapter 00:10.0 SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01) 00:11.0 PCI bridge: VMware PCI bridge (rev 02) 00:15.0 PCI bridge: VMware PCI Express Root Port (rev 01) : 00:18.7 PCI bridge: VMware PCI Express Root Port (rev 01) 02:00.0 USB controller: VMware USB1.1 UHCI Controller 02:01.0 Ethernet controller: Advanced Micro Devices, Inc. [AMD] 79c970 [PCnet32LANCE] (rev 10) 02:02.0 Multimedia audio controller: Ensoniq ES1371/ES1373 / Creative Labs CT2518 (rev 02) 02:03.0 USB controller: VMware USB2 EHCI Controller
OpenBSDでもpciを見られる。-vを付けると詳細が出てくる。面倒なら、dmesgかな。
# pcidump Domain /dev/pci0: 0:0:0: Intel 82443BX AGP 0:1:0: Intel 82443BX AGP 0:7:0: Intel 82371AB PIIX4 ISA 0:7:1: Intel 82371AB IDE 0:7:3: Intel 82371AB Power 0:7:7: VMware VMCI 0:15:0: VMware SVGA II 0:16:0: BusLogic MultiMaster 0:17:0: VMware PCI 0:21:0: VMware PCIE : 2:0:0: AMD 79c970 PCnet-PCI 2:1:0: Ensoniq AudioPCI97
arm mmu
何度目かのARM MMU理解への挑戦。
なるほど、コプロは15番で、そこにはレジスタが16本載ってるとな。それで、 キャッシュの制御やらMMUの制御をやってるとな。
実例が無いかと探してみたよ。
MMUを動かすのに特化したサンプルだな。そして、
rpi_start.S 上記は、NetBSDの入り口だったけど、Linuxでは、 /usr/src/linux-source-3.16/arch/arm/kernel/head.Sあたりが相当するらしい。
この2つのソースを見比べてみると、NetBSDは、綺麗、鮮やかな印象を受ける。 リナのそれは、ごちゃごちゃしてて、見る気が起きないな。
dd
とまあ、armを見たわけだけど、ソース読むなら、絶対にBSD系が良いと思うぞ。 素直だし、綺麗だと思う。(大事な事だから2度言いましたよ。世迷いでは ありません)
で、前回はdcだった。次は、ruby語のsuccを実行すると、ddになるんで、ddを OpenBSD上で読んでみる。リナみたいに、お取り寄せは必要無いし、勝手知ったる 我が家ですからね。
rubyを暫くやってなかったんで、上記いまいち自信が無い。調べたら、最新式rubyが OpenBSDにも有るそうなので、入れてみた。
# pkg_add ruby-2.3.1p1 quirks-2.241 signed on 2016-07-29T15:39:09Z ruby-2.3.1p1:libyaml-0.1.6p1: ok ruby-2.3.1p1: ok --- +ruby-2.3.1p1 ------------------- If you want to use this package as your default system ruby, as root create symbolic links like so (overwriting any previous default): ln -sf /usr/local/bin/ruby23 /usr/local/bin/ruby ln -sf /usr/local/bin/erb23 /usr/local/bin/erb ln -sf /usr/local/bin/irb23 /usr/local/bin/irb ln -sf /usr/local/bin/rdoc23 /usr/local/bin/rdoc ln -sf /usr/local/bin/ri23 /usr/local/bin/ri ln -sf /usr/local/bin/rake23 /usr/local/bin/rake ln -sf /usr/local/bin/gem23 /usr/local/bin/gem
yamlがお供にやってきた。名前を普通のにしとくといいよって事なんで、そうして おいてからREPLを起動。
[ob: ~]$ irb irb(main):001:0> 'dc'.succ => "dd"
おお、正解だった。このsuccはpythonにも無い、日本文化の、お・も・て・な・し。
DESCRIPTION The dd utility copies the standard input to the standard output, applying any specified conversions. Input data is read and written in 512-byte blocks. If input reads are short, input from multiple reads are aggregated to form the output block. When finished, dd displays the number of complete and partial input and output blocks and truncated input records to the standard error output.
こういう代物。512Byte単位でファイルをコピーするのが基本機能。 512Byte単位ってのは、Diskのセクターに書ける基本サイズを意識してのもの。 で、その時に引数を、 name=val 形式で与える事により、ただのcpでは真似が出来ない事を実現してる。
例えば、以前ちょっとやったけど、ファイルの頭から数ブロック飛ばしてコピー するとか、逆に、頭から指定したブロックだけをコピーするとか。 コピーする時に、コード変換を施しながらとか。ここで言うコードは、ASCIIコードと 大型コンピュータで採用されてるEBCDICコードの事。大文字、小文字変換も 出来るって、そこはかとなく昔の仕様を引きずっている感じがするな。
こんなddだけど、BSD系では基幹コマンドの扱いを受けていて、/binの下に 鎮座してる。ヘッダーファイルを含めて、8個で出来上がっていた。もとえ、 これに加えて、manの原稿とMakefileが必須。
今回は、ヘッダーファイルから見ていく。dd.hには、IOって構造体とSTATって 構造体が用意されてた。前者は、文字通り入力と出力の制御情報をまとめて ある。文字デバイスとかパイプとかテープとか読めないデバイスとか、面白い ものが混じっているぞ。
パイプは切捨て出来ないととかテープはseek出来ないよとか注意書きが有るぞ。 って、事は処理を分ける必要が有るんだなと、想像出来る。
STATの方は、文字通り統計情報を管理するまとまりになってましたよ。
それに続いて、各種のフラグビットが定義されてた。これをセットするのは 解析機関の仕事で、使うのは要所々に分散してるんだな。
もう一つ、extern.hが有った。こちらは、関数の型定義と、グローバル変数の 定義が載ってた。関数の引数が全て、voidって事は、全部の主要関数が、 グローバル変数を見て動いているのか。随分昔風の作りだな。
そもそも、EBCDICなんて言う文字コードが出てくる時点で、大型コンピュータと データのやり取りをするために作られたと想像出来る。manに歴史は載って いなかったので、勝手に歴史を調べてみる。
我がunix-v6にddは有ったか? dd page from Section 1 of the unix-6th manualこの通り、ちゃんと有りましたねぇ。
unixより先に大型コンピュータが有ったはずなんで、その頃のunixは、大型コンピュータ では、処理が高価で出来ないような事を、下請けしてたんでしょう。
The UNIX Treeなんて言う、unixの 歴史的ソースを集めた所を見ると、unix-v5の時代にddが登場してますな。 こういう歴史を背負って今のBSDとかが有るのね。
で、先のヘッダーを眺めていると、jclなんて言う意味不な関数が有った。これは何? 定義は、args.cなんて言う、名は体を表すって所に有った。
/* * args -- parse JCL syntax of dd. */ void jcl(char **argv) { struct arg *ap, tmp; char *arg; in.dbsz = out.dbsz = 512; :
JCLを用語事典で引いてみた。 JCLとは|ジョブ制御言語|Job Control Language IT用語辞典
大型コンピュータでプログラムを起動する時の仕様書って事ですかね。 (ついでに、 EBCDICも) そう言えば、このddに与える引数は、unixの流儀に沿っていない。 matzさんが渇望してた、キーワード引数方式で与える事になっている。 例えば、こんな具合にね。
[ob: ~]$ dd if=miniroot-cubie-60.fs of=zzz skip=6144
これだけ前提知識が有れば良いだろう。
ああ、512って暗黙知の数字が、難の説明も無く使われているな。あの人が眼の仇に しそう。他に無いか探ってみたぞ。
[ob: dd]$ grep -n 512 *.[ch] args.c:96: in.dbsz = out.dbsz = 512; args.c:313: * b - multiply by 512. args.c:339: num *= 512; args.c:396: * b - multiply by 512. args.c:418: num *= 512;
いにしえのコードでも、そのまま出てくるから、正に暗黙知。知らない人はこの 業界のもぐりです。
いにしえのコードの方が優しそうなので、そちらを読んでみるか。
512は、ibsとobsとブロック数を掛け算する、3箇所に出てくる。ibsとobsには、 代入が行われていないので、定数的な使い方をしてる。
なんて言うのは、嘘でーす! と、いもとの2世風(なんのこっちゃ)
if (bs) { ibs = obs = bs; if (conv == null) fflag++; }
bsが優先する仕様なのね。それから、カーニハン&リッチーのスタイルでソースが書かれて いるな。こういうの、ほっとするよ。
でも、ほっとするのは、ここまで。見事と言う程、コメントが書かれていない。 それに、関数の定義の順番が普通はmainが最後に来るのに、一番頭に書かれている。 先のjclなんて名前と言い、これは非unix文化の人が書いたに違いないと、現代の 考古学者は推測しました。
きっと、大型コンピュータをやってた人が、unixを下請けに使う為、書いたんだろうな。 だから、突然EBCDICとのコード変換機能が入っていたりする。
現代OS上で再現させる
絶滅したシベリアの冷凍マンモスからDNAを抽出して、マンモスを再現する計画が進行してるとか。 ならば、ソースからバイナリーを再現してやろう。舞台はOpenBSD。
まず、そのままコンパイルしてみる
[ob: ~]$ cc dd.c |& grep error dd.c:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before numeric constant : dd.c:375: error: 'obs' undeclared (first use in this function) dd.c:386: error: expected expression before '|' token dd.c:418: error: 'atoe' undeclared (first use in this function) dd.c:442: error: too few arguments to function 'exit'
警告は、数え切れないぐらい出て来るので、エラーだけ拾ってみた。全部で56個 有ったよ。楽しみながらエラーを潰していく。昔の文法は、そーなってたのねと 分かって面白かったぞ。
現代のエキスは、#includeでstdio.hを注入しておいた。昔はどうやってたのか 後で調べておけ。多分makeも無い時代だろうから、shellスクリプトを駆使して コンパイルしてたんだろうね。
warningが26個程出てきたけど、無事にコンパイル終了。走らせてみる。
[ob: tmp]$ dd if=ndd.c of=z 24+1 records in 24+1 records out 12308 bytes transferred in 0.000 secs (13907345 bytes/sec) [ob: tmp]$ ./a.out if=ndd.c of=y 24+1 records in 24+1 records out [ob: tmp]$ cmp z y
オリジナルのddと結果が一致したんで、まあ成功ですかね。
昔のmakeを調べてみた。やっぱりそんなの無くて、runって名前に統一された シェルスクリプトが用意されてた。
# chdir usr/source/s1 # ed run 3286 /dd.c/ cc -s -O dd.c .,.+5p cc -s -O dd.c cmp a.out /bin/dd cp a.out /bin/dd cc -s -O df.c cmp a.out /bin/df
これを見ると、どうもテスト用って感じだな。コンパイルしてバイナリーが生成され それと元からあるやつを比較なんて事をやってる。
コンパイラーのフラグ、Oはオプチィマイザー。sはリンカーのフラグ。
-s `squash' the output, that is, remove the symbol table and relocation bits to save space (but impair the use- fulness of the debugger). This information can also be removed by strip.
この時代にもdebuggerは有ったんだな。マニュアルをザット見した限りでは、 coreの検視用機能しかサポートしていない。本来のdebugは、print文を 埋めたバイナリーを走らせて実施してたんだな。
それでdebug出来ないようなcoreしちゃうような時、このプログラムを 使うって算段なんだ。
あっ、cdbなんてのも有るな。こちらは、BPを置いて、途中でプログラムを止める 機能が付いてるよ。systemcallのあの機能を使っているんだな。 また、v6の本を読み直してみるかな。
前回のdcがらみ、古いmanを見ると、あのkenさんの署名が有った。 作成日を見ると、1971/11/3 になってる。日本では文化の日。こういう日に 格調高いプログラムをリリースするって、さすがkenさんだ。
とか言っていたら、kenさんのいたずらを発見。 考えさせられるなあ。
diff of dd
下記は、主な変更パターン。
+#include <stdio.h> -char *ibs 512; +char *ibs = 512; -char etoa[] +char etoa[] = - n =* 1024; + n *= 1024; - exit(); + exit(1); - printf("%l+%l records in\n", nifr, nipr); + printf("%d+%d records in\n", nofr, nopr); - cflag =| UCASE; + cflag |= UCASE; - for(ip=ibuf+ibs; ip>ibuf;) + for(ip=ibuf + (int)ibs; ip > ibuf;) - c = (ibc>>1) & ~1; + c = ((int)ibc >> 1) & ~1;