Not only is the Internet dead, it's starting to smell really bad.:2017年05月中旬

2017/05/10(Wed)

[GIS] 続・国土地理院 基盤地図情報

なんだgithubのアカウントあるやんけ

なのになんであのお察しくださいなダウンロードサービスを作ってしまったのか…

まーあそこで落とせるデータ普通に再配布OKなんで、例えばワイがbitbucketなりにリポジトリ作って配布しようが構わんちゅうのはあるけど。

昔仕事でちょっとOpenLayers/GeoExtとMapServer + PostGISそしてPL/R使ってとある業界向け営業支援のGISシステム作ったことあるけど完全に忘却の彼方でアレやな

[NetBSD][pkgsrc] py27-certbot crash

うーむ、certbot(=python2.7)がクラッシュするのpy27-cryptographyから呼ばれるlibsslの中でか

#0  0x00007f7ff7fd2fc0 in ?? ()
#1  0x00007f7ff1222e51 in ssl_check_clienthello_tlsext_early () from /usr/lib/libssl.so.10
#2  0x00007f7ff122e2e3 in ssl3_get_client_hello () from /usr/lib/libssl.so.10
#3  0x00007f7ff1232abe in ssl3_accept () from /usr/lib/libssl.so.10
#4  0x00007f7ff1239783 in ssl23_accept () from /usr/lib/libssl.so.10
#5  0x00007f7fee89c920 in _cffi_f_SSL_do_handshake (self=0x7f7ff398df18, arg0=0x7f7feff263b0)
    at build/temp.netbsd-6.1_STABLE-amd64-2.7/_openssl.c:50593
#6  0x00007f7ff7725cd8 in call_function (pp_stack=0x7f7feb7fd3b8, oparg=1) at Python/ceval.c:4340
#7  0x00007f7ff772207f in PyEval_EvalFrameEx (f=0x7f7fefbba430, throwflag=0) at Python/ceval.c:2989
#8  0x00007f7ff772621e in fast_function (func=0x7f7ff318a500, pp_stack=0x7f7feb7fd848, n=1, na=1, nk=0)
    at Python/ceval.c:4437
(中略)
#32 0x00007f7ff7680fc6 in function_call (func=0x7f7ff5587668, arg=0x7f7ff397d310, kw=0x0) at Objects/funcobject.c:523
#33 0x00007f7ff764e02b in PyObject_Call (func=0x7f7ff5587668, arg=0x7f7ff397d310, kw=0x0) at Objects/abstract.c:2547
#34 0x00007f7ff766378f in instancemethod_call (func=0x7f7ff5587668, arg=0x7f7ff397d310, kw=0x0) at Objects/classobject.c:2602
#35 0x00007f7ff764e02b in PyObject_Call (func=0x7f7ff0b34780, arg=0x7f7ff7b12050, kw=0x0) at Objects/abstract.c:2547
#36 0x00007f7ff77256de in PyEval_CallObjectWithKeywords (func=0x7f7ff0b34780, arg=0x7f7ff7b12050, kw=0x0)
    at Python/ceval.c:4221
#37 0x00007f7ff776ab9d in t_bootstrap (boot_raw=0x7f7ff21f81f0) at ./Modules/threadmodule.c:620
#38 0x00007f7ff6a0df8e in pthread__create_tramp (cookie=0x7f7feb400000) at /usr/src/lib/libpthread/pthread.c:501
#39 0x00007f7ff6697300 in ___lwp_park50 () from /usr/lib/libc.so.12
Cannot access memory at address 0x7f7feb800000

このPRと似てるんだけどこっちはconnectの最中で死んでるけど、N6はacceptの中で微妙に違う。

さーてどうしようかね…

[SCM] git難しい

P/ 久し振りにgitで大災害起した、間違えて大量にconflict出てるcvs co結果とgit subtree mergeの失敗をそのままcommitしてしまい、修正するのめんどくさくなって どうせ自分が使ってるだけだからと変更前に履歴を巻き戻してpush --forceしたんだけど、どっかで操作失敗したようでその枝にあった修正が全部消えて大草原。

久し振りにreflogのお世話になってしまったksg

2017/05/11(Thu)

[NetBSD] BSD sed(1) fix

@BSD sed(1) a/i/c command bug

こないだのバグ以外にも何かあるやろ~と例のアレ以外のBSD sed(1)のソースを読んでてcompile.cの履歴に

  • FreeBSD (差分)
    Fix from Keith Bostic <bostic@bsdi.com> for bug in sed dealing with
    continuation lines.
    
    Submitted by:	Keith Bostic via Kirk McKusick
    
  • OpenBSD (差分)
    fix for a line continuation bug, more than a year ald. work by mckusick,
    bostic, mark@linus.demon.co.uk, davidg, and bde.
    

というのを見つけたのよね、魔球先生からボス経由での報告だけど何でNだけ20年間忘れられてるんすかね。

可能性としては

  • 黒ヤギさん(クジラ偶蹄目ウシ科ヤギ属)はお手紙を読まずに食べた
  • ハブ(爬虫綱有鱗目クサリヘビ科ハブ属)られた

のいずれかだった可能性だろけ、ああ…これFだけに報告行ってOは拾ってきたパティーンかな。

とりあえずはオレオレN6には入れておこうかとまず現象を確認するべくテストケース…

なーんも
 あ
 りま
   せんで
   し
   た。

うーん20年前という時代のせいか

  • チケットねぇ
  • テストもねぇ
  • barさんとfooさんと数珠を握って空拝む

俺らこんな村~なのでどんなバグなのかはソースから読み取るしか無いんだけど、どうやらsedのコマンドである

  • <位置>a\\\n<文字列> … <位置>の次行に<文字列>を追加
  • <位置>c\\\n<文字列> … <位置>の行を<文字列に>置換
  • <位置>i\\\n<文字列> … <位置>の行に<文字列を>追加

の部分に問題があり、<文字列>の中に「\\\n」による行継続が含まれてる場合のコーナーケースって感じ。

とりあえずソースみながら最小ケース作ってみたけど

$ cat >test.txt
aaa\^D^D
$ cat >test.sed
c\
bbb\^D^D
$ sed -f test.sed test.txt

みたいな感じ、Nだと最後の\の後に改行が無くても勝手に行継続と判断して

bbb

になってしまうんだけど、FやOはちゃんと(?)

bbb\

になる。

んー微妙過ぎてマージするか迷うレベル、もっとパッチの必要性がわかり哲也なケース思いつかんぞ…

ワイ、テキスト処理は即Perlのようなものでカネカネキンコしてしまうのでsed(1)力が低くバグの内容を理解するのに時間かかってしゃーない。

つーかGNU sedもダメっぽいんですが。

$ gsed --version
gsed (GNU sed) 4.4
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jay Fenlason, Tom Lord, Ken Pizzini,
and Paolo Bonzini.
GNU sed home page: <http://www.gnu.org/software/sed/>.
General help using GNU software: <http://www.gnu.org/gethelp/>.
E-mail bug reports to: <bug-sed@gnu.org>.
$ gsed 'c\
> bbb\' test.txt
bbb
$

これ珍POSIX *1的にはどうなるんだろうな…

@BSD sed(1) y command 8bit clean bug

もういっこ別のバグ、こっちも20年モノ。

  • FreeBSD (差分)
    Make 'y' command 8bit clean
    PR: 6458
    
  • OpenBSD (差分)
    make y command 8 bit clean; Elmar.Bartel@informatik.tu-muenchen.de
    

この修正を取り込んでLANG=ja_JP.SJISで半角カナ扱えるまで確認したけど、ほんとはBSD sed(1)もマルチバイト対応とか必要で8bit cleanとか前世紀級の修正してる場合じゃないんだけどNE。

ところで突然関係ない話挟み込むけど、最近驚いたのGoogle Chromeって半角カナの扱いって

  • カーソル移動でカナと(半)濁点の間にキャレットが移動できない(内部的にリガチャ的な扱いになってる?)
  • なのでIMEで「パ」と入力しF7キーで半角カナに変換し、「ハ」を削って「゜」残すのができない
  • 「パ」の前にキャレット移動してDelete押しても「ハ」「゜」2文字いっぺんに消える
  • 「パ」の後にキャレット移動してBackspace押すと「゜」だけ消えて「ハ」が残る

のにビックリした。

まぁそんな話は置いておいて、マルチバイトの文字置換もできるそうGNU sedならね(タートルネック感)

$ echo 'あいうえお' | gsed 'y/あ/ア/'
アいうえお

まぁyコマンド程度ならこっちもすぐ対応できるけど、他のコマンドともなるとそもそもlibc regex(3)がアレなのでなー

そういえば昔のGSoCでmultibyte regex(3)をスクラッチで書くぜと採択されて、 結局 こんな難しいとは…と他人の書いた実装(tre)マージしただけで終わったやつ、結局はagrep(1)が使ってるだけなんやな。

sed(1)をtreのregex(3)互換レイヤだけで対応できるんかなぁ、treは内部的にwchar_tモデルっぽいけども(いちおうmbtowcが見えた)。 それならこれまでのコードの互換性から考えて、Spencer regex(3)をワイド化したnvi-1.81のアレをlibcに持ってくる方が苦労は少ない気がしないでもない。

@BSD sed(1) treats semicolon as part of label (hi, one-liner!)

もういっちょ、sed(1)で改行全部取っ払って一行に連結するのに

$ cat >test.txt
aaa
bbb
^D
$ sed -e '
:loop
N
$!b loop
s/\n//
' test.txt
aaabbb

とかラベル(ドビュッシーではない)やるのをGNU sedだとワンライナーで書けるように

$ sed -e ':loop;N;$!b loop;s/\n//' test.txt

と蝉コロンをデリミタに使えるんだけど、BSD sedは対応しとらんので

$ sed -e ':loop;N;$!b loop;s/\n//' test.txt
sed: 1: ":loop;N;$!b loop;s/\n//": unused label 'loop;N;$!b loop;s/\n//'
aaa
bbb

となってしまうのを、OpenBSDは律儀に 直してたようなのでそれもマージ。

ワイはそもそもワンライナーで実行せずスクリプト書く人なのでな…

*1:珍はPOSIXの枕詞であり語調を整えたり情緒を添える言葉で意味はありません、なお20年動くプログラムとは20年壊れたままなのである。

誤解

億年ぶりにはてブに※ついてる思ったら

ものすごい誤解だ、釣りだったらスマン

2017/05/14(Sun)

[映画] Wim Wenders/Don't Come Knocking(2005)

ヴェンダース監督の「アメリカ、家族のいる風景(Don't Come Knocking)」をようやく観た。

彼の代表作「パリ、テキサス」以来20年ぶりにサム・シェパードを脚本にタッグを組んだ作品なので、公開当初から気にはなっていたけど未見のままだった。

あの名作のコンビとあって期待値が高過ぎたせいか一般的な評価はあまり芳しくない、自分は好きだけれどね。

そもそも「アメリカ~」は「パリ~」の続編ではないのだけれども、同じく彼の代表作である「ベルリン・天使の詩」で、天使ダミエルが人間界に身を堕として一人の女性を愛することで生きる喜びを知るストーリーの続編に「時の翼にのって~ファラウェイ・ソー・クロース!」でダミエルを羨んだ天使カシエルがやはり人間になるも犯罪に加担するまで落ちぶれ、贖罪として命を落とすというバッドエンドを持ってきて低評価を受けたのとよく似ている。

一般受けはどうしてもロマンティックな方に軍配が上がっちゃうからこれはもう仕方がない。

「パリ~」は共依存に陥った男女が人生もろとも破綻し、ふたりの関係はもう戻らないけれどもまだ幼い息子とだけは家族の絆を取り戻すという、こちらもロマンティックな話なんだけど、「アメリカ~」は放蕩の限りを尽くしてきた男がミッドライフ・クライシスを迎え、それまで存在すら知らなかった子供をダシに過去の女に縋ろうとし拒絶される話で、人生経験の豊富でない若い男女が観て感動する話ではないのは確かである。

しかし同年に何かと比べられることの多いジム・ジャームッシュ監督もストーリーまる被りの「ブロークン・フラワーズ」を撮影してるんだけどシンクロニシティだね。 こういう役を演じさせるならサム・シェパードよりもビル・マーレイの方が向いてるし、そこがそれぞれの映画の点数の差なんだろう。

オープニングは アーチーズ国立公園の、まるで神の両眼かと思わせる洞窟からのぞく青空、そして大自然が作り出した砂岩のアーチの下を、主人公の西部劇俳優ハワード(サム・シェパード)が馬で疾走するシーンからはじまる。

「パリ~」も人間の存在を許さないかのような虚無が支配するモハビ砂漠を、僅かな水も尽きてなお一心不乱に歩く主人公トラヴィス(ハリー・ディーン・スタントン)から物語はスタートした。

トラヴィスの行動は自殺行為ではあるけれども彼は死にたいわけじゃない、死んだ父母が結婚し自分を生んだ地(テキサス州パリス)、そこにはかつて気まぐれで通信販売で購入した空き地があり、そこへたどり着ければまた人生をやり直せるといういわば双六の「振り出しに戻る」という行為に妄執するがゆえの行動。

一方でハワードの行動はより短絡的かつ破滅的であり、映画の撮影現場から逃亡しあわよくば落馬事故で死んでしまいたいという自殺衝動。 「ライト・スタッフ」でサムの演ずるチャック・イエーガーが死をも恐れぬ自身のテストパイロットしても勇猛さの誇示に馬を走らせた演出との対比をも感じさせる。

砂漠で一夜を明かしひとまず憑き物が落ちたハワードは馬と身にまとった派手なカウボーイ衣装を捨て、身を隠す先として母の住む故郷へと決めるけれどもそれは思いつきでしかない。トラヴィスが弟ウォルトに何度も引き戻されようが隙あらば逃げ出し向かおうとしたパリスほどの思いは無い。

ハワードのロケバスには

こっちくんな(Don't come knocking)

の文字、これもドラヴィスが行き倒れた砂漠を越えた先のバーのカウンターに掛けられた

砂埃まみれ(の店)、座るでも立ち去るでも何でもご自由に(The dust has come to stay. You may stay or pass on through or whatever)

の看板 *1を思い出させる。これまですべてを拒絶してきた男ハワードと、翻弄され流されるままだったトラヴィスとの性格の違いを表しているのだろうか。

ハワードはどこからか車と携帯電話を手に入れて、夕暮れのハイウェイを走りながら長らく連絡を絶っていた母へ電話をかける。このシーンもトラヴィスがウォルトの運転する車でモーテルへ向かうシーンによく似ている(嵐が訪れる予感をさせる美しい夕焼け)。ハワードの惨めな心境そのままの歌詞を歌う若い男は(まだ物語の上では明かされないが)はハワードの(存在すら知らなかった)息子アール、トラヴィスもこのシーンで彼の失踪後にウォルトが引き取って育てていた息子ハンターの存在が明かされる。

車と携帯を捨てバスで母の家へ向かう道中にハワードは道端で全知全能の神の存在について歌う謎の男とすれ違う、これもトラヴィスがウォルトの元に身を寄せつかの間の安寧を得るけども眠れぬ夜に街を彷徨う折に「どこにも安全な場所など存在しない」と叫ぶ狂人と出会い、今の居候生活を続けることは出来ない事に気づくシーンを思い出させるけれど、いまいちストーリーとの関連性がわからない。

ハワードを追いかけるのは映画会社のエージェントで氷のように冷徹で彼を映画の撮影現場に連れ戻すという任務以外には何一つ興味を示さない男、トラヴィスを追いかけた弟ウォルトが常識人で温かい家庭を持ちとにかくトラヴィスに理解を示すのとは対極である。

字数が尽きた、まだ続くかもしれないし続かないかもしれない何でもご自由に。

*1:ネオアコバンドMexico 70のアルバムタイトルにもなってるね。

2017/05/19(Fri)

[NetBSD] debugging BSD sed(1) (その4)

オレオレN6にOでの変更は-i(inplace edit)以外はとりあえず全部mergeし終わった、-iについてはNのHEADもOも他の変更と一緒にミソクソでmergeしててコード履歴がクッソ汚いので パクリ元のFの変更を追いながら再実装することにして、とりあえず今度はFの変更履歴を最初から追ってる最中。

そんでFからの変更取込みがミソクソになるのも必然なのが判った、sedのコード修正してる連中ほとんどテストも書かずリグレッション何それうまいの状態で、変更ひとつ引っ張ってくると別の場所が壊れますわこれ。

さっきもGとHの動作が変という

の修正を取り込んだら、最終行に改行の無い入力やバイナリデータに対しても改行が強制される別のバグが爆誕して、そっち調べたら

が10年も経ってからようやく報告されてるレベル、その間に-iの実装でコード大きく変わってるのでそのまま適用できんしワイいまどうしようか検討中。

そんな感じで心の中の ICBMボタンを連打してながらソース読んでるんですが、-iオプション(inplace)ではなくて全く別の話の'i\'コマンド(insert)の方の話になるんだけど、FreeBSDでは

というこれまた古いPRが上がってて、これはFでは

の修正でfixされてるんだけども、他のOSでは

という状態なんよね。

なのでオレオレN6にマージしようかと思ったんだけどこの修正がまた無茶苦茶なんだよな。

--- head/usr.bin/sed/main.c	2000/05/11 16:57:45	60393
+++ head/usr.bin/sed/main.c	2000/05/11 17:01:52	60394
@@ -115,6 +115,7 @@ main(argc, argv)
 	char *argv[];
 {
 	int c, fflag;
+	char *temp_arg;
 
 	(void) setlocale(LC_ALL, "");
 
@@ -129,7 +130,10 @@ main(argc, argv)
 			break;
 		case 'e':
 			eflag = 1;
-			add_compunit(CU_STRING, optarg);
+			temp_arg=xmalloc(strlen(optarg) + 2);
+			strcpy(temp_arg, optarg);
+			strcat(temp_arg, "\n");
+			add_compunit(CU_STRING, temp_arg);
 			break;
 		case 'f':
 			fflag = 1;

うーん-eに渡されたスクリプト全部まるっとコピーして改行強制ってすげー無駄、sed -fせずにsed -eにARG_MAX何それで長文書く人結構いそうだしなぁ、というか居たSIerやはり絶滅以下略。

しかしこれ最終行の改行有無に関するバグをこれまで散々踏み抜いてるのにこの対応ができるってはっきり言って何も考えてないだろ(怒)。 つーかその後に消してまた戻すとかモグラ叩きもいいとこだしなぁ。

まっとうな方法を考えてみると、簡単なのはiコマンドの実行時(process.cのprocess関数)

			case 'i':
				(void)printf("%s", cp->t);
				break;

の部分を修正して

@@ -166,6 +166,8 @@ redirect:
 				break;
 			case 'i':
 				(void)printf("%s", cp->t);
+				if ((len = strlen(cp->t)) == 0 || cp->t[len - 1] != '\n')
+					putchar('\n');
 				break;
 			case 'l':
 				lputs((const char *)ps);

で対応できる、けれど処理対象のストリームやファイルを一行づつ処理する度にstrlen(3)が呼ばれて性能悪化しそうなのがアレ。

ただまぁこれは毎回strlen(3)呼ばんでもsedスクリプトをコンパイルする時(compile.cのcompile_stream関数)の

		case TEXT:                      /* a c i */
...
			cmd->t = compile_text();
			break;

の時点で文字列は確定してるので

@@ -80,6 +80,7 @@ struct s_command {
 struct s_command *next;		 /* Pointer to next command */
 struct s_addr *a1, *a2;		 /* Start and end address */
 	char *t;				 /* Text for : a c i r w */
+	size_t n;				 /* Length of Text */
 	union {
 		struct s_command *c;		 /* Command(s) for b t { */
 		struct s_subst *s;		 /* Substitute command */

みたいにstruct s_commandに文字列長のフィールドを追加して

@@ -261,6 +261,7 @@ nonsel:	/* Now parse the command */
                                error("extra characters after \\ at the end "
                                    "of %c command", cmd->code);
                        cmd->t = compile_text();
+                       cmd->n = strlen(cmd->t);
                        break;
                case COMMENT:                   /* \0 # */
                        break;

とコンパイルの時点で長さを事前に計っておいて、さっきのprocess.cを

@@ -166,6 +166,8 @@ redirect:
 				break;
 			case 'i':
 				(void)printf("%s", cp->t);
+				if (cp->n == 0 || cp->t[cp->n - 1] != '\n')
+					putchar('\n');
 				break;
 			case 'l':
 				lputs((const char *)ps);

と書きかえればマシになる、またstrlen(3)使わなくてもcompile_text()の中で返す文字列の長さは判ってるので

@@ -261,6 +261,7 @@ nonsel:	/* Now parse the command */
                                error("extra characters after \\ at the end "
                                    "of %c command", cmd->code);
-                       cmd->t = compile_text();
+                       cmd->t = compile_text(&cmd->n);
                        break;
                case COMMENT:                   /* \0 # */
                        break;

としてそっちでセットするようにすれば、コンパイル時コストも増えないし。

それに他のa/rコマンドですでに無駄に毎回strlen(3)呼ばれるのも不要になるよねこれ

			case 'a':
...
				appends[appendx].type = AP_STRING;
				appends[appendx].s = (const char *)cp->t;
				appends[appendx].len = strlen(cp->t);
				appendx++;
				break;
...
			case 'r':
				appends[appendx].type = AP_FILE;
				appends[appendx].s = (const char *)cp->t;
				appends[appendx].len = strlen(cp->t);
				appendx++;
				break;

また長さが事前に判ってればprintf("%s")という無駄に重いフォーマット命令使ってるとこでふつーにfwrite(3)が使えるようになるし。

@@ -166,6 +166,8 @@ redirect:
 				break;
 			case 'i':
- 				(void)printf("%s", cp->t);
+ 				(void)fwrite(cp->t, sizeof(*cp->t), cp->n, stdout);
+				if ((len = strlen(cp->t)) == 0 || cp->t[len - 1] != '\n')
+					putchar('\n');
 				break;
 			case 'l':
 				lputs((const char *)ps);

まー結論としては、モグラ叩きデバッグとその結果をただ漫然とコピペコーディングやってるといつかモグラが堀った穴で地盤沈下して埋もれて死ぬってこった。