MongoDB

とある朝の買い物帰りの出来事。一方通行の道を水前寺清子風に颯爽と歩いていると(トボトボだと爺くさいですからね)、年寄りマークの軽トラが前方に停止した。

運転席のドアがバタンと開き、それを閉めるでもなく、爺さんが飛び出してきた。そして、堂々と白昼にも関わらず、立ちションを始めた。こう堂々とやられるとすがすがしい。(んな事は、無いそ) 全くもう、トイレに入っても、ドアを閉めない派ですか?

公道で、ドアを開けたままって、交通往来妨害罪ですかね。それと、立ちションで、軽犯罪なんですかね?

「立ちション」って犯罪なの? 外で尿意をもよおしたときに注意すべきポイント。みんな経験有るから、こういう記事になってるんだな。

件の爺さんは、農家の人らしく、畑に向かって放尿してた。どうせやるなら、肥料の代わりに なれば良いという、もったいない精神が発露してたんだな。それとも、有機農法実践者? と言う事で、見なかった事にしよう。

で、更にさっそうと歩いていたら、電柱に迷い犬のビラが貼ってあった。その手配書によると、 トイプードル、体重4kg、性格は温厚ですって。こんな手配書初めてみたと女房に言うと、あちこちに貼ってあったとか。

散歩の途中ででも逃げ出したんですかね。それとも室内で飼われていて、本格的立ちションを したくて、脱走したんですかね?

どこかのメーカーが、犬用のおむつと言うか、立ちション禁止帯を宣伝してた。犬にとっちゃ、 迷惑至極。逃げ出したくもなりますよ。

幸い、オイラーは人間様。迷惑かけないように立ちションしよう。なんてったって、尿意を我慢 出来ない、お年頃だもの。どこかに、立ちションの作法とか出てないですかね。きっと、美学が 有るに違いない。

秋葉原のホームで糞した糞爺は、美学に反しますな。 「大便騒動」新宿駅に続き秋葉原駅でも  利用客が目撃した「衝撃の場面」とは

timezone

前回やったOpenBSDのupgradeで、timezoneの設定が上手くいかず、間に合わせでGMTになって しまった。ls -lとかで出て来る時刻情報は、ローカルタイムになるんだけど、dateコマンドで 出て来るやつは、ローカルタイムなのにGMTってなっちゃう。実害が無いので我慢してるんだけど、プチ負けた気になる。

これもそれも、原因は起動の度にカーネルを構成するファイル類が再配置されるんで、configで 書き換えた変更情報が元に戻ってしまう事にある。これを修正するなら、再配置の元ファイルを 変更するしかない。

となると、timezoneの元データを格納してる場所を突き止めるしかない。そしてその場所に バイナリーパッチを施す。

修正の第一歩は、場所を突き止める事だ。configコマンドで指定したのは、timezoneって文字列。これを手掛かりに、場所を探してみる。

$ find /usr/src/sys | xargs grep -l timezone
/usr/src/sys/conf/param.c
/usr/src/sys/dev/pci/mbg.c
/usr/src/sys/dev/usb/umbg.c
/usr/src/sys/isofs/cd9660/cd9660_node.c
/usr/src/sys/isofs/udf/udf_vnops.c
/usr/src/sys/kern/kern_time.c
/usr/src/sys/kern/subr_userconf.c
/usr/src/sys/kern/syscalls.master
/usr/src/sys/sys/kernel.h
/usr/src/sys/sys/syscall.h
/usr/src/sys/sys/syscallargs.h
/usr/src/sys/sys/time.h

さて、現場は何処でしょう? ホームズ君宜しく推理します。消去法を適用。ヘッダーファイルは無実だろう。param.cとかkern_time.cとかが怪しそう。subr_userconf.cは、多分configコマンドの下請けだろうね。まず、それを見た。そしたらtzって言う構造体を外部参照してたよ。 よって、こいつは無実。

ええい、param.cを見てみるか。

#ifndef TIMEZONE
# define TIMEZONE 0
#endif
#ifndef DST
# define DST 0
#endif

struct  timezone tz  __attribute__ ((section(".data"))) = { TIMEZONE, DST };

どうも、これっぽいな。カーネルをコンパイルする時に、make -DTIMEZONE=-540 とかやらないと、TIMEZONE宣言は未定義になる。よってdefineが生きて、0に設定。そいつらが、 dataセクションのtzにセットされるんだな。

ここまでの推理を検証。param.oのデータセクションにtzが有るはず。

# nm /usr/share/compile/GENERIC.MP/param.o
  :
00000000 D hz
00000020 D maxfiles
00000018 D maxprocess
0000001c D maxthread
00000004 D tick
00000008 D tickadj
0000000c D tz

有名処が色々出てきた。やはりこのファイルに定義元が有るんだな。 ここで、リンカ・ローダ本が登場します。binaryHack本は、Linux向けなので敬遠です。 それによると、readelfで、セクション情報を調べろとな。

# readelf -S param.o
There are 18 section headers, starting at offset 0x11e8:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
    :
  [ 3] .data             PROGBITS         0000000000000000  00000040
       0000000000000070  0000000000000000  WA       0     0     4

ここで、offsetに注目。0x40ってなってるので、ファイルの先頭から0x40進んだ所から テーブルが始まっているそうです。そしてそのサイズは、0x70.

# readelf -x 3 param.o

Hex dump of section '.data':
  0x00000000 00000000 00000028 00002710 00000064 d....'..(.......
  0x00000010 0000079e 0000051e 00000b93 00000000 ................
  0x00000020 00000008 00000010 00040000 00001b76 v...............
  0x00000030 00000001 00002000 00000800 00000014 ......... ......
  0x00000040 0000000a 00002000 00000080 00000080 ......... ......
  0x00000050 00000064 0000003c 0000001e 0000003c <.......<...d...
  0x00000060 00004000 00007fff 00000070 0000000a ....p........@..

セクションが上では3番のインデックスになってるんで、それを頼りにダンプ。 nmで出てきたtzの値が0xcなんで、それだけオフセットを持った所が、tzの値になってる はず。なんですが、書き換えるの怖い。

自分で、一度コンパイルし、次にtzの値を-540(-9時間)にして、コンパイル。出来た ものを比較しましょ、って作戦で行きます。 (param.cだけをコンパイルしようとしたら、ヘッダーが所定の位置になくて、エラー発生。 よって、普通にカーネルをコンパイルする)

# mv param.o z.o
# vi param.c             ;; set -540
# make
# cmp -l param.o z.o
    77 344   0
    78 375   0
    79 377   0
    80 377   0

本当は、make -DTIMEZONE=-540 で、行けるはずなんだけど、有効にならなかったので、ソースファイルを修正した上でコンパイルした。

/*
 * System parameter formulae.
 *
 * This file is copied into each directory where we compile
 * the kernel; it should be modified there to suit local taste
 * if necessary.
 *
 * Compiled with -DHZ=xx -DTIMEZONE=x -DDST=x -DMAXUSERS=xx
 */

param.cには、こんなコメントが入っているんだけどね。Makefileには、-DMAXUSERS=80が 登録されてた。そこに、configとoptionsも見とけってあったんで、optionsを見たら

option "TIMEZONE=value"
     value indicates the time zone offset of the hardware realtime clock
     device, in minutes, from UTC.  It is useful when the hardware realtime
     clock device is configured with local time, when dual-booting OpenBSD
     with other operating systems on a single machine.  For instance, if the
     hardware realtime clock is set to Tokyo time, value should be -540 as
     Tokyo local time is 9 hours ahead of UTC.  Double quotes are needed when
     specifying a negative value.

make時にアドホックに指定するのは、忘れっぽいおまえには無理なんで、設定ファイルに書いて おけとな。Japan/Tokyoのオイラー向け解説がなされていたぞ。

指示通りに、GENERIC.MPに、optionを設定したら、Makefile内に、-DTIMEZONE-540の 設定が現れた。これで納得しましたよ。(configをすっ飛ばして、Makefileに直接書き込んでおくのも有りか)さて、本題に戻ります。

cmpの -l オプションが、旧石器時代の挙動には、困ったものだ。

     -l      Print the byte number (decimal) and the differing byte values
             (octal) for each difference.

byte numberも1から始まっているしね。

(gdb) print/x 76
$1 = 0x4c
(gdb) p/x 0344
$2 = 0xe4

cmpが言ってくる番号が一つずれているので、76を変化が有ったアドレスとして、16進数に直してみた。(ついでに、バイトデータの8進数も直してみた)そして、その付近をダンプ。ああ、上でreadelfで調べた時、0x40から0xcだけ変位してるはずってなったけど、それと符合したね。

# hexdump -C param.o
 :
00000040  64 00 00 00 10 27 00 00  28 00 00 00 e4 fd ff ff  |d....'..(.......|

一応、16進数を10進数に直しておく。dオプションはgdbで符号付きって事なんだけど、そうなっていなかった ので、引き算してみた。

(gdb) p/d 0 - 0xfffffde4
$1 = 540

ひょっとして、gdbで扱う整数が64Bitデフォじゃないかと思い、プチ実験。

(gdb) p/x -540
$1 = 0xfffffde4
(gdb) p/d $1
$2 = -540
(gdb) p/d 0xfffffde4
$3 = 4294966756
(gdb) p/d 0xfffffffffffffde4
$4 = -540

ちょいと釈然としない所が有るけど、まあ、そんなものと思っておこう。あこがれの64Bit マシン上で有りますからね。

これで、自信を持って書き換え出来るな。勿論、hexeditの登場。書き換えた後、Ctl-Xでsaveするか破棄するか選べるよ。

フーリエ級数

ふと、フーリエ級数の事を調べていたんだ。そしたら、こんなのが出てきた。 フーリエ変換を宇宙一わかりやすく解説してみる

で、実際にやってみようとなった。maximaで方形波もどきを発生させる式を立て、それを 観測しようと言う作戦。

(%i7) w(x) := sin(x) + 0.2 * sin(3*x) + 0.1 ;
(%o7)                 w(x) := sin(x) + 0.2 sin(3 x) + 0.1
(%i8) integrate(w(x)*sin(3*x), x, 0, 2 * %pi) ;

rat: replaced 0.1 by 1/10 = 0.1

rat: replaced -0.2 by -1/5 = -0.2
 :
rat: replaced 0.2 by 1/5 = 0.2
                                6 %pi - 1   1
(%o8)                           --------- + --
                                   30       30

でも、何だか変! ratって何よ? 30秒考えて、有理数って思いついた。正確を期すため、 浮動小数は、有理数に直しましたって言ってるんだな。分からないと面喰らうな。

(%i10) w(x) := sin(x) + sin(3*x)/5 + 1/10 ;
                                         sin(3 x)   1
(%o10)                  w(x) := sin(x) + -------- + --
                                            5       10
(%i11) integrate(w(x)*sin(3*x), x, 0, 2 * %pi) ;
                                6 %pi - 1   1
(%o11)                          --------- + --
                                   30       30

今度は、何の警告も出ずにすぱっと答えが出てきた。定積分の威力だなあ。

これで、フーリエ級数の求め方が分かったので、今度は、プローブ周波数を色々と 変化させてみたい。再帰させる? 普通にループが有るみたい。

Functions and Variables for Program Flow

(%i6) for a:0 thru 5 do print(a, a^2) $
0 0
1 1
2 4
3 9
4 16
5 25

ちょっと実験してみた。こうやって使うのね、了解です。

newlispのdatabase取り扱い

標準提供されてるモジュール内に、有名どころのDBモジュールが用意されてる。

ODBCってのは、ほぼWindows用なのね。それ以外は、MySQLとPostgressSQL、SQLite3って 具合に提供されてるんで、DB接続で困る事はなかろう。OpenBSDにSQLite3 が入っていたので、試してみると

$ newlisp
newLISP v.10.7.1 64-bit on BSD IPv4/6 UTF-8, options: newlisp -h

> (module "sqlite3.lsp")

ERR: user error : cannot find sqlite3 library
called from user function (module "sqlite3.lsp")

こういう場合は、慌てず騒がず、ライブラリィーを確認

    "/usr/local/lib/libsqlite3.so.13.3" ; OpenBSD 4.6

メンテナンスされてなかったので、37.1に修正。

モジュールをロードするとsqlite3を縦横無尽に使えるようになる(はず)テストモジュールが 入っているので、走らせてみる。

> (test-sqlite3)
database opened/created,  ... Ok
created table fruits,  ... Ok
inserted, last row id: 1,  ... Ok
 :
try to drop table fruits via SQL injection attack ... no luck, table was safe against SQL injection.
deleted, rows affected: 4,  ... Ok
tables: ("fruits"), ... Ok
columns: ("name" "qty" "price" "blobtext"), ... Ok
table fruits dropped,  ... Ok
true

りんごとかバナナ等のデータを突っ込んで試験してる。SQLインジェクションが失敗してる事を 確認してるな。どんな風に悪い菌を注入しようとした? そっちの方に興味が有るな。

        ; SQL injection has no chance:

        (print "try to drop table fruits via SQL injection attack ... ")

        (if (sql3:sql "select * from fruits where name = ?;" '("''; drop table \
fruits;"))
                (println "OUCH! Table was dropped via SQL injection!!!")
                (println "no luck, table was safe against SQL injection."))

穴埋めの?が、SQLを突っ込まれるのを守りましたって事かな? 昔ちょっとSQLを触ったけど、 英語風言語に、正直辟易したのを覚えているぞ。

そんなオイラーには、SQLを追放したDBの方が向いているな。で、最近流行りのNoSQLです。

MongoDB

NoSQLの有名なやつとして、MongoDBってのが有るそうだ。最近これの開発元が株を公開し、 大きな評判になったらしい。第二のぐぐるを目指してください。

で、こやつはRDBみたいにきっちりしたものではなく、ゆるやかなDBだそうだ。

Mongo (from "humongous") is a high-performance, open source,
schema-free, document-oriented database. A common name in the
"NOSQL" community.

WWW: http://www.mongodb.org/

Debianなら、mongodb mongodb-devを入れておくといいのかな。先回りして -devも入れといた。 入れた途端に、サーバーが走り出していたよ。

deb9:~$ ps awx | grep mongo
   529 ?        Ssl    0:15 /usr/bin/mongod --unixSocketPrefix=/run/mongodb --config /etc/mongodb.conf

confファイルが有るとな。どんな設定が出来るか見ておく。

# mongodb.conf

# Where to store the data.
dbpath=/var/lib/mongodb

#where to log
logpath=/var/log/mongodb/mongodb.log

logappend=true

bind_ip = 127.0.0.1
#port = 27017

# Enable journaling, http://www.mongodb.org/display/DOCS/Journaling
journal=true
 :

DBは例外なく、クラサバ構成。自ホストからしか接続出来ないのがデフォの仕様とな。そして DB領域が、どのぐらいDISKを消費してるかと言うと

deb9:~$ du -sh /var/lib/mongodb/
201M    /var/lib/mongodb/

合わせて、200Mか。データの出し入れで増えて行くんだろうね。使われなくなったエリアは 勝手にGCしてくれるのだろうか? それとも、ツールか何かがあって、それで掃除と言うか、 断捨離を実行するのかな?

deb9:~$ ls -lh /usr/bin/mongo*
-rwxr-xr-x 1 root root  14M Dec 16  2016 /usr/bin/mongo
-rwxr-xr-x 1 root root  29M Dec 16  2016 /usr/bin/mongod
-rwxr-xr-x 1 root root 9.4M Dec 16  2016 /usr/bin/mongodump
-rwxr-xr-x 1 root root 7.6M Dec 16  2016 /usr/bin/mongoexport
-rwxr-xr-x 1 root root 7.6M Dec 16  2016 /usr/bin/mongofiles
-rwxr-xr-x 1 root root 7.7M Dec 16  2016 /usr/bin/mongoimport
-rwxr-xr-x 1 root root 7.4M Dec 16  2016 /usr/bin/mongooplog
-rwxr-xr-x 1 root root  29M Dec 16  2016 /usr/bin/mongoperf
-rwxr-xr-x 1 root root  11M Dec 16  2016 /usr/bin/mongorestore
-rwxr-xr-x 1 root root  12M Dec 16  2016 /usr/bin/mongos
-rwxr-xr-x 1 root root  29M Dec 16  2016 /usr/bin/mongosniff
-rwxr-xr-x 1 root root 7.7M Dec 16  2016 /usr/bin/mongostat
-rwxr-xr-x 1 root root 7.6M Dec 16  2016 /usr/bin/mongotop

これがmongo一族か。随分と太ったやつがいるな。東アジア一帯に生息するモンゴロイドは、 幼少の頃、ケツが青くて、全体に瘦せ型が特徴。それって、蒙古族じゃん。

大きいのをlddしたら成分に、libboost_system.so.1.62.0とか libstdc++.so.6が含まれていた。Cフラフラ語が出目なんだな。

色々と付属品が有るんで、どんな芸を見せてくれるか、後で調べてみよう。それよりも、クライアントを動かしてみれ。

deb9:~$ mongo
MongoDB shell version: 3.2.11
connecting to: test
> help
        db.help()                    help on db methods
        db.mycoll.help()             help on collection methods
        sh.help()                    sharding helpers
        rs.help()                    replica set helpers
        help admin                   administrative help
        help connect                 connecting to a db help
        help keys                    key shortcuts
        help misc                    misc things to know
        help mr                      mapreduce

        show dbs                     show database names
        show collections             show collections in current database
        show users                   show users in current database
        show profile                 show most recent system.profile entries with time >= 1ms
        show logs                    show the accessible logger names
        show log [name]              prints out the last segment of log in memory, 'global' is default
        use <db_name>                set current database
        db.foo.find()                list objects in collection foo
        db.foo.find( { a : 1 } )     list objects in foo where a == 1
        it                           result of the last line evaluated; use to further iterate
        DBQuery.shellBatchSize = x   set default number of items to display on shell
        exit                         quit the mongo shell

MongoDB入門(MongoDBシェル版)が、基本になるな。読んでみよー。最近はぐぐるブラウザーが勝手に翻訳してくれるから、楽でいいわい。