The Man Who Fell From The Wrong Side Of Sky:最新 5 日分

2019/10/23(Wed)

[オレオレN6] 続・pkg_add(1) won't work with libarchive 3.4.0

前回は原因をarchive_write_data_blockと断定してしまったけど、ワイのgrep(1)ミスであり同じエラーメッセージを表示するarchive_write_header側の問題であった、メンゴメンゴ(死語)。

    683 static int
    684 extract_files(struct pkg_task *pkg)
    685 {
...
    779                 r = archive_write_header(writer, pkg->entry);
    780                 if (r != ARCHIVE_OK) {
    781                         warnx("Failed to write %s for %s: %s",
    782                             archive_entry_pathname(pkg->entry),
    783                             pkg->pkgname,
    784                             archive_error_string(writer));
    785                         goto out;
    786                 }

archive_write_data_blockは3.3.3→3.4.0でコードに変更はないので変だなと思って再度コード検索し直して気づいた。

最初はarchive_write_data_blockには ドキュメントと実装の相違があって、バイナリ互換性壊すし将来リリースで直すわという結論になっとるのでその関係かなと思ったんだけど無駄な時間だったね(およそ5分)。

ちなみにその部分の実装を軽く読んでみると

[libarchive/archive.h]
    191 #define ARCHIVE_EOF       1     /* Found end of archive. */
    192 #define ARCHIVE_OK        0     /* Operation was successful. */
    193 #define ARCHIVE_RETRY   (-10)   /* Retry might succeed. */
    194 #define ARCHIVE_WARN    (-20)   /* Partial success. */
    195 /* For example, if write_header "fails", then you can't push data. */
    196 #define ARCHIVE_FAILED  (-25)   /* Current operation cannot complete. */
    197 /* But if write_header is "fatal," then this archive is dead and useless. */
    198 #define ARCHIVE_FATAL   (-30)   /* No more operations are possible. */

[libarchive/archive_write_disk_posix.c]
   1545 static ssize_t
   1546 _archive_write_disk_data_block(struct archive *_a,
   1547     const void *buff, size_t size, int64_t offset)
   1548 {
   1549         struct archive_write_disk *a = (struct archive_write_disk *)_a;
   1550         ssize_t r;
   1551
   1552         archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
   1553             ARCHIVE_STATE_DATA, "archive_write_data_block");
   1554
   1555         a->offset = offset;
   1556         if (a->todo & TODO_HFS_COMPRESSION)
   1557                 r = hfs_write_data_block(a, buff, size);
   1558         else
   1559                 r = write_data_block(a, buff, size);
   1560         if (r < ARCHIVE_OK)
   1561                 return (r);
   1562         if ((size_t)r < size) {
   1563                 archive_set_error(&a->archive, 0,
   1564                     "Too much data: Truncating file at %ju bytes",
   1565                     (uintmax_t)a->filesize);
   1566                 return (ARCHIVE_WARN);
   1567         }
   1568 #if ARCHIVE_VERSION_NUMBER < 3999000
   1569         return (ARCHIVE_OK);
   1570 #else
   1571         return (size);
   1572 #endif
   1573 }

と将来的に修正する準備としてARCHIVE_VERSION_NUMBERでifdefしとる、でもこれ設計的にはこれプロトタイプ変更して

ようにすべきよね、まぁ人は愚かなので滅びるまで設計ミスは無くならんしこれ以上つっこまんとこ。

ということで仕切り直してarchive_write_headerの3.3.3→3.4.0への変更点をざっと眺めてみる。

--- libarchive.orig/files/libarchive/archive_write_disk_posix.c  2019-04-10 17:24:05.000000000 +0900
+++ libarchive/files/libarchive/archive_write_disk_posix.c      2019-10-04 23:49:49.000000000 +0900
@@ -165,6 +165,10 @@
 #define O_NOFOLLOW 0
 #endif

+#ifndef AT_FDCWD
+#define AT_FDCWD -100
+#endif
+
 struct fixup_entry {
        struct fixup_entry      *next;
        struct archive_acl       acl;
@@ -348,6 +352,8 @@

 #define HFS_BLOCKS(s)  ((s) >> 12)

+
+static int     la_opendirat(int, const char *);
 static void    fsobj_error(int *, struct archive_string *, int, const char *,
                    const char *);
 static int     check_symlinks_fsobj(char *, int *, struct archive_string *,
@@ -401,6 +407,37 @@
                    size_t, int64_t);

 static int
+la_opendirat(int fd, const char *path) {
+       const int flags = O_CLOEXEC
+#if defined(O_BINARY)
+           | O_BINARY
+#endif
+#if defined(O_DIRECTORY)
+           | O_DIRECTORY
+#endif
+#if defined(O_PATH)
+           | O_PATH
+#elif defined(O_SEARCH)
+           | O_SEARCH
+#elif defined(O_EXEC)
+           | O_EXEC
+#else
+           | O_RDONLY
+#endif
+           ;
+
+#if !defined(HAVE_OPENAT)
+       if (fd != AT_FDCWD) {
+               errno = ENOTSUP;
+               return (-1);
+       } else
+               return (open(fd, path, flags));
+#else
+       return (openat(fd, path, flags));
+#endif
+}
+
+static int

はい、POSIX:2008で新規に追加されたopenat(2)のラッパーが追加されとるわね。

このopenat(2)ってsyscallは以前にも 解説したTickTokなのかTOCTTTTTTTTOOOOOUUUUUUなのか毎回綴りを思い出せないファイルシステムの競合状態に関する脆弱性への対策として導入されたもの。 この問題は古くより存在するopen(2)が相対パスを処理する際、起点となる現在の作業ディレクトリはプロセス単位でグローバルでないためスレッドセーフではないことで起きる。 なので明示的に起点をファイルディスクリプタとして引数に渡すもの。

もしこのAPIはじめて知ったなんて人おったら、もう追加されて干支一回りしとるので勉強してどうぞ( プレゼンでかるく触れた記憶があるぞ)。

ともかくN6の時点ではこのopenat(2)は未実装だったので、ラッパー中のエミュレーションコードが使われ結果としてバグっとるちゅーことなんやな。

なのでN6をとっくに切り捨てた現在のpkgsrcでは問題は起きないという事、もちろんマルチプラットホームを標榜するpkgsrcのサポートするOSの中でopenat(2)がまだ未実装のものものもあるだろうし、そっちでは当然発生すると思われる。 まあでもそんな環境でpkgsrc使う人なぞ世界で3人くらいしかおらんだろうから見過ごされとるんだろう。

んで再度さっきの差分を読むと

という破綻間違いなしの実装になっとるので、ここで引っかかっとるんだろうなと想像がつく。

ということでlibarchive 3.4.0に対してすべき作業は、完全なopenat(2)エミュレーションとして

を実装するかなんだけど、そもそもlibarchiveのAPIでこのエミュレーションを呼びだす箇所は

   1948         /* Try to record our starting dir. */
   1949         a->restore_pwd = la_opendirat(AT_FDCWD, ".");
...
   2642         chdir_fd = la_opendirat(AT_FDCWD, ".");
   2643         __archive_ensure_cloexec_flag(chdir_fd);
...
   2705                 } else if (S_ISDIR(st.st_mode)) {
   2706                         if (!last) {
   2707 #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
   2708                                 fd = la_opendirat(chdir_fd, head);
   2709                                 if (fd < 0)
   2710                                         r = -1;
   2711                                 else {
   2712                                         r = 0;
   2713                                         close(chdir_fd);
   2714                                         chdir_fd = fd;
   2715                                 }
   2716 #else
   2717                                 r = chdir(head);
   2718 #endif
...
   2811 #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
   2812                                         fd = la_opendirat(chdir_fd, head);
   2813                                         if (fd < 0)
   2814                                                 r = -1;
   2815                                         else {
   2816                                                 r = 0;
   2817                                                 close(chdir_fd);
   2818                                                 chdir_fd = fd;
   2819                                         }
   2820 #else
   2821                                         r = chdir(head);
   2822 #endif

のように、HAVE_OPENATが定義されてない限りはAT_FDCWDつきで呼ばれとるんだよね…なので完全なエミュレーションは不要なはずなんだけど。

ということでもうちょっとコードを読み進めないとならんのだけど、いつ認知症老人による失火で焼け死んでも不思議でない明日は無い状態なので次回は未定。

2019/10/20(Sun)

[オレオレN6] libarchive 3.3.3 → 3.4.0へのアップグレードでbootstrapから入れたpkg_installが無事死亡

丸一日チラシの裏死んでおったけどようやく復旧、今回もpkg_rolling-replace走らせたら途中で止まっとって壊滅ちゅーパターンなので、そろそろチラシの裏も続けるなら他のOSに変更したいところではある。

そんでログをみるとpkg_install/add/perform.cの

    665                 r = archive_write_data_block(writer, buff, size, offset);
    666                 if (r != ARCHIVE_OK) {
    667                         warnx("Write error for %s: %s", filename,
    668                             archive_error_string(writer));
    669                         return -1;
    670                 }

のメッセージが出力されとったので、pkgsrc/packages/All以下に作成されたバイナリパッケージをpkg_add(1)しようとして死んどるもよう。

ので犯人はlibarchiveと断定、いったん3.3.3に巻き戻しあらためてbootstrapからやりなおした。

どうもうち以外では問題になっとらんようなので、N7以降では顕在化しないバグなんかなぁこれ。

2019/10/19(Sat)

[Windows] 死を招く古いグラフィックドライバとWindows 10(19H1以降)でのリモートデスクトップ

最近のWindows 10(19H1以降)、RDPでの接続に時間がかかったり接続エラーになったりブラックアウトやログインでのフリーズそしてとどめにBSoDからの再起動という現象がでて困っとったんだけども、どうやらグラボの問題なんやな。

例えばAMDはRadeon 4000以前のグラボはWindows 10サポートは打ち切ったぜと 公式リリース出しとるようで、自分とこで不具合が発生する環境は正にこいつRadeon HD 4200なのであった、合掌。

要はRDPがハードウェアアクセラレーションでドライバの非互換性(DirectX?)を踏んでクラッシュしとるちゅーこと、なお問題のマシン(HP Microserver N54L)に対応グラボを増設する余地は無し、無念。

しゃーないので回避策としてハードウェアアクセラレーションを無効にするためレジストリに

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Avalon.Graphics]
"DisableHWAcceleration"=dword:00000001

を追加して再起動、とりあえずこれだけでRDPは安定して使えるようになるもよう。

2019/9/13(Fri)

[写真] SONY製ミラーレスカメラからPlayMemories Camera Appsのサイトにログインできないのは2段階認証のせい

ちょっと前までのSONYのミラーレスカメラと一部のコンデジには PlayMemories Camera Appsというアップデートソフトを有償購入し、カメラに新機能を追加することができた。

なぜ「できた」と過去形かというと、よっぽど売れなかったのか最新機種(α7IIIおよびα6600以降)ではこの機能消されとるんだよね、短い命であった南無南無。

つーかワイも所有のNEX-5R用にいくつかアプリ買ったんだけど、アプリストアの出来が酷いのですわ。 「カメラの中身はLinux + ARMやしフルブラウザとIME(たぶんNetFront + POBox)搭載しときゃ何とでもできるやろ!」というクッソ安易なコンセプトで実装されとって非常に使いづらい。 コンパクトにこだわったボディの小さな背面液晶にほぼPC用サイトそのままのページを表示しやがるので、メインユーザー層たるオッサンジーサンの老眼じゃ字読めねえわ、スタイラスペンも無しでこのサイズのタッチパネルのキーボード操作なんぞ無理よ無理無理かたつ無理なのである。 そして搭載されてるCPUがしょせんカメラ用の非力なものなので、タップからワンテンポ遅れる文字入力の動作がもっさりで死ぬ、そりゃ流行りませんわこれ。

更に酷い事にこのPlayMemories Camera Appsのストアサイト、PSN Accountで2段階認証もといSMSによる複数要素認証を有効にしてるとログインできねえのですわ。

はい、エラーメッセージもなにも表示されんのでまず普通の人は原因は判らんしカメラ本体の故障かと思いますわね。そりゃ誰も使わねぇよこんなん。

ちなみにPCからログインした場合でも

という問題が発生する、よってPC経由のインストールすらままならない状態なのですわ。

これ「アプリ売れねーな!じゃあ機能廃止!」という以前に、もしかして実は誰もストアにログインしてアプリを買えない状態だったのでは…? あるいは世間一般において複数要素認証の認知度ってのはゼロに等しくて誰も使っておらず問題にならなかったのか(なんとかPayのように!なんとかPayのように!)

まぁ2段階認証をきちんと設定するようなセキュリティ意識の高い人であれば、これPSN Accountが仕様変更で2段階認証に対応した時か My SONY IDとの認証共通化の際に、このストアで正しく動作するかテストせずにリリースされ放置されっぱなしの結果まともに動かないのでは…?ということに気づくわけです。

んじゃあどうやってログインするか、スマホなんかだと2段階認証に対応しとらん古いOSであれば、アプリパスワードを発行して対応することもできる。 そんでPSN Accountにおいても2段階認証の設定項目に「機器設定パスワード」というのがあって生成できるんだけど、これ入力してもカメラからだとログインできないのだ。 但し書きにゲーム機とスマホって書いてあるからUser Agentかなにかで蹴ってるんだろう。

つーことでどうしてもカメラにアプリをインストールしたいのであれば「一時的に2段階認証を切る」というクソ運用が必要になるわけですバーカバーカ。

ワイが中古のNEX-5R買ってアプリ入れたの1~2年くらい前でその当時からすでにこの問題あったんだけど、いっこうに直る気配も障害情報も上がってこないとこを見ると「何年経ってもSONYのソフトウェア軽視という病は直らねえ」ってこった、いい加減にしろ莫迦。 暇な人はメール報告でもしてあげてください、ワイはめんどくさいしもう買うことも無いからね…

余談、この手の拡張機能を別売りするというコンセプトはもう30年以上前の発売になる Minolta α-7700iの時代から存在していて、「 インテリジェントカード」というICカードはけっこうな数が売れたんだよなぁ、やはりMinoltaは時代を先取りし過ぎていたのだ。

他社からもAndroid搭載して追加アプリケーションをストアから購入できる機種がでていたりもするけど、あまり流行る気配は無さそうね。 まぁ携帯音楽プレーヤーにAndroid搭載もあまり流行らんし、これはもうカメラというセグメントがスマホに完全に喰われてしまった結果やろうね。 あのボトムズのスコープドッグみたいなiPhone 11といいスマホカメラも迷走しまくってる感があるけど。

2019/9/2(Mon)

[オレオレN6] math.h(libm) vs cmath(libstdc++)

前回ちょっと書いたように、オレオレN6のgccは4.5.3とクソ古いので-std=c++11を要求するものがビルドできねえのでmk.confにGCC_REQD=8としてgcc8を使ってるのだけど、それでもなおビルドが通らないケースが多くて困る。

というのもlibstdc++においてC++11で導入されたcmathの新機能はlibmの同等の機能、例えばstd::round()であればround()を呼びだす事で実装されてるんだけど、N6のlibmにおいては一部の関数が未実装なので、c++config.hで_GLIBCXX_USE_C99_MATH_TR1が未定義となり一律無効化されてしまうので、-std=c++11する意味がねえのですわ。

$ grep _GLIBCXX_USE_C99_MATH_TR1 /usr/pkg/gcc8/include/c++/x86_64--netbsd/bits/c++config.h
/* #undef _GLIBCXX_USE_C99_MATH_TR1 */

libstdc++/configureを確認すると_GLIBCXX_USE_C99_MATH_TR1を有効にする為に現状で不足しとる関数は

acoshl
asinhl
atanhl
cbrtl
erfl
erfcl
exp2l
expm1l
fma/fmaf/fmal
hypotl
lgammal
llrintl
llroundl
log1pl
log2l
lrintl
lroundl
nearbyint/nearbyintf/nearbyintl
nexttowardf/nexttowardl
remainderl
remquol
rintl
roundl
scalbln/scalblnf/scalblnl
scalbnf/scalbnl
tgammal
truncl

うーん結構な数あるのよね、N8のlibmに更新すればかなりの部分が実装済ではあるんだけど、それでもなお

expm1l
lgammal
log2l
remainderl
remquol
tgammal

あたりは未実装なもよう。

なのでtextproc/icuとかビルドするとこんなエラーが出るわけだ。

c++ -I/usr/include -I/usr/pkg/include -D_REENTRANT -DU_HAVE_ELF_H=1 -DU_HAVE_NETBSD_ATOMIC_OPS=1 -DU_HAVE_ATOMIC=1 -DU_HAVE_STRTOD_L=0 -I. -I../common -DU_ATTRIBUTE_DEPRECATED= -DU_I18N_IMPLEMENTATION -O2 -march=i486 -I/usr/include -I/usr/pkg/include -W -Wall -pedantic -Wpointer-arith -Wwrite-strings -Wno-long-long -std=c++11 -c -o number_decimfmtprops.ao number_decimfmtprops.cpp

number_decimalquantity.cpp: In member function 'void icu_60::number::impl::DecimalQuantity::_setToDoubleFast(double)':
number_decimalquantity.cpp:387:40: error: 'round' is not a member of 'std'
     auto result = static_cast<int64_t>(std::round(n));
                                        ^
number_decimalquantity.cpp:387:40: note: suggested alternative:
In file included from /usr/pkg/gcc48/include/c++/cmath:44:0,
                 from number_decimalquantity.cpp:9:
/usr/pkg/gcc48/lib/gcc/i486--netbsdelf/4.8.5/include-fixed/math.h:347:8: note: 'round'
 double round(double);
        ^
../config/mh-bsd-gcc:43: recipe for target 'number_decimalquantity.ao' failed
gmake[1]: *** [number_decimalquantity.ao] Error 1

他にもdevel/cmakeとかわりと重要なシロモノが同様のエラーでビルドできひんので、連鎖的にビルド不能に陥るパッケージ多過ぎィ!で困るのよね。

とりあえずtextproc/icuやdevel/cmakeでエラーになる箇所はlibmに実装はあるので、この場合は回避策はあって

--- i18n/number_decimalquantity.cpp.orig        2018-03-26 13:38:30.000000000 +0000
+++ i18n/number_decimalquantity.cpp     2018-05-28 02:21:50.000000000 +0000
@@ -391,7 +391,7 @@ void DecimalQuantity::_setToDoubleFast(d
         for (; i <= -22; i += 22) n /= 1e22;
         n /= DOUBLE_MULTIPLIERS[-i];
     }
-    auto result = static_cast<int64_t>(std::round(n));
+    auto result = static_cast<int64_t>(round(n));
     if (result != 0) {
         _setToLong(result);
         scale -= fracLength;

としてcmathでなくmath.hのround関数を使うようなkludge patchを適用すればとりあえず何とかなる、でもこれビルド止まる度にこの手のパッチ書くのもめんどくせえよなぁ。

とりあえずコード監査途中で飽きて放置中のOpenSSLの件が片付いたら、次はlibmをとりあえず最新にしてそれから未実装の関数どうにかするかなんやな。