9front (4)
朝雪が降っていたけど止んで、陽が差してきたので散歩に出た。と、車と人通りが少ない新興住宅地にさしかかった所、道路の真ん中でおじいさんが尻もちをついていた。
手招きされた。どうしたんです?(そんなの見れば分かるじゃん。我ながら情けない問い。) ろれつが回らない風。朝っぱらから飲んだくれ? でもない。
ころんで起き上がれなくてSOSが発信されてるんだよ。近づいてみると、杖をお持ち。自助努力で立ち上がろうとするが、足腰が弱っていてだめ。
手を出してきたんで、その手をつかんで立たせてあげようとするも、ガタイが大きくてオイラーには無理。更に両手を掴んで立たせようとするも、途中までたって、元も木阿弥。
後ろに回って、背中から抱きかかえて、重い荷物を持ち上げる要領でやったら、何とか立たせて あげられた。第三の足、杖も使えて、やっと3点支持で自立できたぞ。
おっかなびっくりに支えていた手を放すと、一歩二歩と亀の歩みで動き出した。オイラーよりも 背丈は高いし、防寒具のダブダブを除いても断然に恰幅が良い。
あいさつは言葉にならず、頭を下げるだけ。きっと脳卒中か何かに不自由になったのでしょう。 オイラーのn年後を見てるような気がして思わず、『情けは人の為ならず』を思い出したぞ。
その時は気が動転してたけど、後で思い出すと、首から下げていた携帯は通話を試みたように、 蓋が開いた状態になってた。多分、助けを呼ぼうとしたけど手袋が障害になって電話出来なかったんだろうな? それとも、特殊な携帯でSOSを発信出来るようになっていたのかな?
あと、お洒落な帽子と派手な黄色の防寒着を召されていたな。きっと家族の思いやりがこもって いるんだろう。それから、ほのかに香水と言うかオーディコロンの匂いがしたように思う。 手を鼻に近づけたら、確かに良い香りがした。お洒落な人だったんだなあ。
nc of OpenBSD
前回、Plan9port(in OpenBSD)に入ってるdial(1)をちょっと触った。同様な機能の物がncである。OpenBSDにも勿論入っているので、gdbにかけて動きを追ってみたい。それには、ncの 再コンパイルが必要だな。/usr/src/usr.bin/ncに置いてあるMakefileにちょっと細工する。
CFLAGS= -g
そしてコンパイルすれば良い。その点、p9pや9frontのそれは何もしなくても、最初からacidに かかるようになってる。cmdだけじゃなくてlibもacidですいすいて潜っていける所が、Linuxには無い醍醐味である。
今回は、IPアドレスとかで指定するんじゃなくて、FQDNで指定してみて、どう動くか見る。 日頃沢山アクセスが有るであろうヤッホーをターゲットにする。あれあそこってググル様のご指導によりhttps化されてるよね。そのポート番号って確か443番だったはず。じゃヤッホーのIPは知ってるか? そういう場合にプロはdigとかを使うらしいけど、こちとらはアマチュアなんで、軽くお茶を濁しておく。
$ host www.yahoo.co.jp www.yahoo.co.jp is an alias for edge.g.yimg.jp. edge.g.yimg.jp has address 183.79.248.252
(gdb) r www.yahoo.co.jp https Starting program: /usr/src/usr.bin/nc/nc www.yahoo.co.jp https Breakpoint 1, main (argc=3, argv=0x7f7ffffe91f8) at netcat.c:152 152 int ch, s = -1, ret, socksv;
お決まりのmainで止めて、丹念に追って行くと、コマンドラインの入力を内部変数に取り込んでいた。
381 } else if (argv[0] && argv[1]) { 382=> host = argv[0]; 383 uport = argv[1];
更に進めて行くと、portの名前を数字に置き換えるルーチンに出会った。
(gdb) bt #0 strtoport (portstr=0x7f7ffffe936f "https", udp=0) at netcat.c:1380 #1 0x00001dc345b040e7 in build_ports (p=0x7f7ffffe936f "https") at netcat.c:14\29 #2 0x00001dc345b026ab in main (argc=2, argv=0x7f7ffffe9200) at netcat.c:636
で、その中身。
1378 if ((entry = getservbyname(portstr, proto)) == NULL) 1379 errx(1, "service \"%s\" unknown", portstr); 1380=> return ntohs(entry->s_port);
それが済むと、コネクトの部分に行く。
892remote_connect(const char *host, const char *port, struct addrinfo hints) 893{ 894 struct addrinfo *res, *res0; 895 int s = -1, error, on = 1, save_errno; 896 897=> if ((error = getaddrinfo(host, port, &hints, &res0))) 898 errx(1, "getaddrinfo for host \"%s\" port %s: %s", host, 899 port, gai_strerror(error));
getaddrinfoの第三引数にホスト名をIPaddressに変換(DNSを引く)格納するんだな。ちなみに、第一、第二の引数は次の通り。
(gdb) p port $7 = 0x1dc5c748fb80 "443" (gdb) p host $8 = 0x7f7ffffe935f "www.yahoo.co.jp"
この後、タイムアウト付きでconnectされるようになってた。
dial of 9front
今度は9frontでやってみる。
open("/net/cs", 2) return value: 3 pwrite(3, "tcp!www.yahoo.co.jp!https", 25, 4294967295) return value: 25 seek(0x00007a0c, 3, 0, 0) return value: 0 pread(3, 0xdfffed8c, 127, 4294967295) return value: 32 data: "/net/tcp/clone 182.22.31.252!443" open("/net/tcp/clone", 2) return value: 4 pread(4, 0xdfffe9dc, 255, 4294967295) return value: 1 data: "2" pwrite(4, "connect 182.22.31.252!443", 25, 4294967295) return value: 25 open("/net/tcp/2/data", 2) return value: 5 close(4) return value: 0 close(3) return value: 0 526: breakpoint _exits+0x5 INTB $0x40
どうやら、/net/csが、host名とport名の解決問い合わせだな。そして、そこから返ってきた データを使って接続するとな。unixのネットワーク関連は、ごちゃごちゃしてて捻くれていて 悪いインターフェースの見本だ。カリフォーニアの人が、あっけらかんと動けばいいじゃんと 言う態度で実装したに違いない。
それで、東海岸の人が綺麗に実装しなおしてみせたんだな。
下記はちょっとしたacidの使い方。
acid: bpset(filepc("dial:45")) acid: cont() 511: breakpoint dial+0x4a CMPL 0x114(SP),$0x0 acid: src(*PC) /sys/src/libc/9sys/dial.c:45 40 ds.local = local; 41 ds.dir = dir; 42 ds.cfdp = cfdp; 43 44 _dial_string_parse(dest, &ds); >45 if(ds.netdir) 46 return csdial(&ds); 47 48 ds.netdir = "/net"; 49 rv = csdial(&ds); 50 if(rv >= 0) acid: mem(dial:ds, "7s") tcp *!http tp (null) (null) (null) (null)
もうネット方面はこれぐらいにしておくかな。
python
何処にでも生息する蛇が9frontにも、御多分に漏れず居るそうなので。
term% python Python 2.5.1 (r251:54863, Oct 30 2017, 03:58:19) [C] on plan9 Type "help", "copyright", "credits" or "license" for more information. >>>
ちょっと古いけどね。で、へそ曲がりな事に、pythonとのセッションはunix側の端末には一切 流れてこないので、rioのGUI画面で結果をファイルにコピペした。表示方法はpython独自な やり方をしてるんだろうか? どんな方法? pythonの巣ごもりで、独自の環境を作って その中で表示するとか。だから、unix側に開いているパイプの一端にはやり取りが流れない。
なにかヒントが無いかと思って、過去のpythonとの戯れを思い出してみると、どんな風に コンパイルされたか等を白状するモジュールが有った事を思い出した。
term% python -m ./sysconfig.py Traceback (most recent call last): File "/sys/lib/python/runpy.py", line 85, in run_module loader = get_loader(mod_name) File "/sys/lib/python/pkgutil.py", line 456, in get_loader return find_loader(fullname) File "/sys/lib/python/pkgutil.py", line 466, in find_loader for importer in iter_importers(fullname): File "/sys/lib/python/pkgutil.py", line 417, in iter_importers raise ImportError("Relative module names not supported") ImportError: Relative module names not supported
見事にエラー。わざと出目を隠していないかい! どんなコードになってるか行番号を頼りに 覗いてみたいものだ。そんなの簡単 cat -n でしょ。ブブー、シンプルを旨とするplan9のcatには、そんなオプションは無い。 ソフトウェアの単純さとか、 忍び寄る機能主義は、興味深い記事。
そういう時は、edの登場です。
term% cd /sys/lib/python/distutils term% ed sysconfig.py 19248 ,n 1 """Provide access to Python's configuration information. The specific 2 configuration variables available depend heavily on the platform and 3 configuration. The values may be retrieved using : 536 get_config_vars().get(name) 537 """ 538 return get_config_vars().get(name) Q term%
目的ファイルを読み込み、カンマnを実行。カンマは、1,$の省略と見做されますんで、全行をn(行番号付きで)表示しなさい。最後にQコマンドで、ファイルに書き込む事無く終了。 馬鹿とはさみは使いようですね。
Ruby 1.8.xをPlan9で動かす、ってpythonだけじゃやだって方の労作です。
sys/doc
/sys/docの下に、いわゆるシステムの取り扱い説明書が置いてある。ご丁寧にps形式だったりms形式だったりhtml形式だったりだ。manの生原稿が有れば、形式の変換はお手の物。 unix開発の公式理由は、写植システムの開発ってのが有るんで、面目が保たれているんだ。
でも、それを隠れ蓑にして、 開発を快適に行うためにOSを整備したり、もろもろのツールを作ったり(開発に行き詰まった時に使う、息抜き用のゲームも必需品)したという、おおらかな時代。outputを厳密に求められない佳き環境(研究所)が有ったというから恵まれていたな。
で、どんなのが有るか見てみたい。使い道の余りなさそうな蛇に登場願おう。
term% cd /sys/doc term% python -m SimpleHTTPServer 80 Serving HTTP on 0.0.0.0 port 80 ... 10.0.2.2 - - [20/Dec/2017 14:36:21] "GET / HTTP/1.1" 200 - 10.0.2.2 - - [20/Dec/2017 14:36:21] code 404, message File not found 10.0.2.2 - - [20/Dec/2017 14:36:21] "GET /favicon.ico HTTP/1.1" 404 - 10.0.2.2 - - [20/Dec/2017 14:38:08] "GET /net/net.html HTTP/1.1" 200 - 10.0.2.2 - - [20/Dec/2017 14:38:08] "GET /net/tree0.png HTTP/1.1" 200 - 10.0.2.2 - - [20/Dec/2017 14:38:08] "GET /net/net1.png HTTP/1.1" 200 - 10.0.2.2 - - [20/Dec/2017 14:39:17] "GET /9.html HTTP/1.1" 200 -
同じものがNet上にも有ったぞ。 Plan 9 — The Documents (Volume 2) と思ったら、中身が空じゃん。 The Organization of Networks in Plan 9こちらの方は中身が詰まっているな。
Implementation Plan 9 C Compilers に面白い記述が有ったぞ。
SPARC kc kl ka Power PC qc ql MIPS vc vl va Motorola 68000 1c 1l Motorola 68020 2c 2l ARM 7500 5c 5l Intel 960 6c 6l DEC Alpha 7c 7l Intel 386 8c 8l AMD 29000 9c 9l
これの類を何処かで見た事が有る。えーとね、えーとね。golangのソース上。但し、最近のgoは 自分自身で自分をコンパイル出来るようになってるので(セルフコンパイル)入っていないはず。
FreeBSDのportsを探ったら、最近の1.9.2用に並行して、go14が置いてあった。このgo14が 各アーキテクチャ用の最後の世代なんだな。これが有るとboot用のgoが作れて、それを使って 最新式のgoを構築出来るとな。go14を入れてみた。
[fb11: cmd]$ pwd /usr/local/go14/src/cmd [fb11: cmd]$ ls 5a/ 6g/ addr2line/ gc/ objdump/ 5c/ 6l/ api/ go/ pack/ 5g/ 8a/ cc/ gofmt/ pprof/ 5l/ 8c/ cgo/ internal/ yacc/ 6a/ 8g/ dist/ ld/ 6c/ 8l/ fix/ nm/
ARM,Intel 960,Intel 386に対応してるとな。開発者が同じだと、名前の付け方も一緒か。 9frontに手を出すような好き者じゃなくても、8xぐらいは眺めておいた方が良いかも。
// Inferno utils/8l/asm.c // http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c // // Copyright 1994-1999 Lucent Technologies Inc. All rights reserved. // Portions Copyright 1995-1997 C H Forsyth (forsyth@terzarima.net) // Portions Copyright 1997-1999 Vita Nuova Limited // Portions Copyright 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) // Portions Copyright 2004,2006 Bruce Ellis // Portions Copyright 2005-2007 C H Forsyth (forsyth@terzarima.net) // Revisions Copyright 2000-2007 Lucent Technologies Inc. and others // Portions Copyright 2009 The Go Authors. All rights reserved.
と、一部を覗いてみたぞ。 Lucent Technologies Inc ってなってるけど、その前身はATTの 誇るベル研。unix生誕の地。goにもunixの血が流れているのがこの広告ではっきりしたな。
先のplan9のマニュアルを(斜めに)見ていたら、ndbの説明が出てた。詳細はndb(6)に詳しいんだけど、発見が有った。
term% cd /lib/ndb term% grep http * common:tcp=http port=80 common:tcp=https port=443 common:tcp=vnc-http port=5800
commonって名前のファイルが、unixで言う /etc/sevicesの役目を担っているのね。親切に vnc用の奴まで載ってるよ。
と思ったら、real dns root server ips も掲載。 これって、unix界でもたまに更新されるファイルだったな。えと、何て言う名前だ? 思い出されないので OpenBSDで漁ってみたら、/usr/src/usr.sbin/bind/lib/dns/rootns.cにハードコートされてた。
static char root_ns[] = ";\n" "; Internet Root Nameservers\n" ";\n" "$TTL 518400\n" ". 518400 IN NS A.ROOT-SERVERS.NET.\n" : "A.ROOT-SERVERS.NET. 3600000 IN A 198.41.0.4\n" "A.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:BA3E::2:30\n" : "M.ROOT-SERVERS.NET. 3600000 IN A 202.12.27.33\n" "M.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:DC3::35\n";
変化するDNSとサーバー証明書の関係~「ランチのおともにDNS」より最近のDNSって、超責任重大な事になってるのね。知らんかったわい。
ip protocol numbers には、ipのプロトコル番号が4とか、tcpは6とかudpは17とか、他の 知らないものが多数列挙されてた。/etc/protocols も兼ねているんか。 これで、胸のつかえが降りたよ。
Plan9のネットワークって面白いな。次の記事はその一例。 ネットワークはどう抽象化されるのか?
build kernel
で、面白い機能はどう実現されてる?ネットワークアクセスと言っても、下支えしてるNICがあってこそ実現可能。となれば、カーネルの出番。いよいよカーネルをコンパイルしてみる。そこからカーネルの何かが分かるだろう。FAQの案内に則って、
term% pwd /sys/src/9/pc term% time mk >LOG processing ../boot/bootfs.proto file system made 4.07u 1.29s 6.75r mk
pcってのは、i386なマシンの事ね。この他にpc64とかbcm(arm)とかも有る。 一応、コンパイル時間と、ログを残すようにしてみた。7秒でコンパイル完了とな。機能を 絞っているんで、コンパイル行数が少ないんだな。小粒なOpenBSDでもカーネルをコンパイルすると3分ぐらいはかかっていたはずだから、雲泥の差だ。
term% ls *.8 | wc 211 211 2096
211個の部品を組み合わせて、9pcと言うカーネルが出来上がるとな。
--rwxrwxr-x M 26 glenda sys 97 Dec 21 16:20 reboot.out --rw-rw-r-- M 26 glenda sys 3512 Dec 21 16:20 init.h --rw-rw-r-- M 26 glenda sys 17769 Dec 21 16:20 pc.c --rwxrwxr-x M 26 glenda sys 689 Dec 21 16:20 init.out --rw-rw-r-- M 26 glenda sys 355 Dec 21 16:20 reboot.h --rw-rw-r-- M 26 glenda sys 1723346 Dec 21 16:20 bootfs.paq --rw-rw-r-- M 26 glenda sys 988 Dec 21 16:20 apbootstrap.h --rw-rw-r-- M 26 glenda sys 2260 Dec 21 16:20 errstr.h --rwxrwxr-x M 26 glenda sys 222 Dec 21 16:20 apbootstrap.out --rwxrwxr-x M 26 glenda sys 50037 Dec 21 16:20 boot --rw-rw-r-- M 26 glenda sys 28453 Dec 21 16:20 sd53c8xx.i --rw-rw-r-- M 26 glenda sys 9191919 Dec 21 16:20 pc.root.s --rw-rw-r-- M 26 glenda sys 703 Dec 21 16:20 pc.rootc.c --rw-rw-r-- M 26 glenda sys 8705 Dec 21 16:20 LOG --rwxrwxr-x M 26 glenda sys 4409685 Dec 21 16:20 9pc
namespace
9frontの大きな特徴としてnamespaceってのが有るそうな。オイラーにとっちゃ意味不なんで 取り合えず、man 4 namespace してみた。
user's profileが実行されると、何でもファイルに見立ててアクセスできるようになるとな。 unixみたいにネットワークを使う時、socketして種を作り、bindでIP Addressとportを紐付けてからconnectで接続するなんていう変な作法は無し。
で、manが言う事には、便利なファイルの口が多数紹介されてた。 丁度FreeBSDあたりのhier(7)の気分。面白そうなので、ちょいとその一部を挙げてみた。 これって、9front内を歩き回る時の便利な地図と思われるぞ。
/386/mkfile Selected by mk(1) when $objtype is 386, this file configures mk to compile for the Intel x86 architecture. /lib/ndb The network database used by the networking software; see ndb(6) and ndb(8). /lib/namespace The file used by newns (see auth(2)) to estab- lish the default name space; see namespace(6). /cfg/system System-specific files, often addenda to their namesakes, notably cpurc, termrc, namespace, and consoledb. /net/cs The communications point for the connection server, ndb/cs (see ndb(8)). /net/dns The communications point for the Domain Name Server, ndb/dns (see ndb(8)).
そして、その地図が現実にはどうなってるか確認出来る。下記も、一部を抜粋したもの。
term% ns bind /root /root mount -aC '#s/boot' /root bind / / bind /386/bin /bin bind -a /rc/bin /bin bind /net /net bind -a '#l' /net mount -C '#s/boot' /n/other other bind -c /n/other/usr/glenda/tmp /usr/glenda/tmp bind -c /n/other/usr/glenda/tmp /tmp bind -a /usr/glenda/bin/rc /bin bind -a /usr/glenda/bin/386 /bin mount '#s/rio.glenda.457' /mnt/wsys 1 mount -b '#s/rio.glenda.457' /dev bind /net/tcp/1/data /dev/cons cd /usr/glenda
xxx/binを/binにかぶせてしまうので、/binをアクセスするだけで、必要な実行ファイルを全て手中に出来るという仕掛けなんだな。これを見て、以前入れたfindを/usr/glenda/bin/386の 下に移動しといた。これで、findって叩くだけで、何処にいても利用出来る。
上の地図を使って、面白い物を発見。
term% cat /adm/users -1:adm:adm:glenda 0:none:adm: 1:tor:tor: 2:glenda:glenda: 10000:sys::glenda 10001:map:map: 10002:doc:: 10003:upas:upas:glenda 10004:font:: 10005:bootes:bootes:
このファイル、どうやらunixで言う、/etc/passwdと/etc/groupを兼ねたものらしい。 uid:user-name:group-name:add-group こんな意味を持ってるのかな。
sshfs
ふとした事からsshfsなんてのを知った。NFSの現代風なやつである。NFSだと管理者が厳格に 管理するんだけど、sshfsは通信にsshを使う、ユーザーが勝手に相手先の任意な場所を、手元の任意な場所に見せる事が出来る。市場開放と言うか規制緩和策である。
FreeBSDだとportsになってるんで fuse-sshfsを入れるだけ。但し使うまでにちょっとした 前準備が必要。
[fb11: kernel]$ sudo kldload fuse [fb11: ~]$ sudo sysctl vfs.usermount=1 vfs.usermount: 0 -> 1 [fb11: ~]$ sshfs sakae@debian: /home/sakae/linux [fb11: ~]$ ls linux/ ALL GZ/ bsd/ qhs/ src/ [fb11: ~]$ df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/da0s1a 30450744 9715788 18298900 35% / devfs 1 1 0 100% /dev tmpfs 3597392 4 3597388 0% /tmp /dev/fuse 31347568 15361392 14370768 52% /usr/home/sakae/linux [fb11: ~]$ umount /usr/home/sakae/linux
ユーザーレベルのファイルシステム(fuse)が下敷きになるんで、モジュールをロード。ユーザーがマウント出来るように許可。手元(使うユーザーが読み書き出来るdir、この場合はlinux)に マウントポイントを用意。後はsshfsを実行。ネットの向こうにあるdebianのhomeがlinuxに現れた。使い終わったらumount。
リナちゃんだと、もう少し簡便で、ただ使うだけ。下記の場合はTop-dirを丸ごとbsd配下に 晒す事になる。
deb9:~$ sshfs sakae@freebsd:/ /home/sakae/bsd
なんだか、plan9ぽくないかい。
年の終わりのお約束
そして、こちらは、お正月のお楽しみ用かな。
今年の更新は、これにて終了。来年も宜しくお願い致します。