2021年8月18日 (水)

小ネタ:adb start-serverできないときの対処

0. TL; DR

netsh interface portproxy reset でポート プロキシ構成をリセットする

1. 解説

普段使いのWindows機で久しぶりにAndroidアプリを書こうと思い、エミュレータを起動したときのこと。

エミュレータなので起動タイムアウトしたようで、adb serverの起動が失敗したとみなされたようだ。
以下はadb serverを起動しようとした時の出力。

  PS C:\Users\f97on> adb devices
  adb.exe: failed to check server version: protocol fault (couldn't read status): No error
  PS C:\Users\f97on> adb start-server
  * daemon not running; starting now at tcp:5037
  could not read ok from ADB Server
  * failed to start daemon
  error: cannot connect to daemon
  PS C:\Users\f97on> adb kill-server
  error: failed to read response from server
  PS C:\Users\f97on> adb start-server
  error: protocol fault (couldn't read status): No error

adb serverが起動しないことにはアプリを実行できないので、エラーメッセージをもとにググる。

すると、「netsh interface portproxy reset でポート プロキシ構成をリセットすると回復した」という記事を発見。
実際にやってみる。

  PS C:\Users\f97on> netsh interface portproxy reset

  PS C:\Users\f97on> adb start-server
  * daemon not running; starting now at tcp:5037
  * daemon started successfully

おかげさまで無事エミュレータと通信できるようになった。

2020年5月30日 (土)

WSL2にした話

0. ついに Windows 10 version 2004 が GA

先日、ようやくWindows 10 version 2004がGAになったので入れてみた。
今回の目玉の一つはWindows Subsystem for Linux(WSL) version 2(以下「WSL2」)だろう。

僕はすでに既存のWSLでUbuntuを使っていたので、公式の移行手順をもとにUbuntuを更新を開始。

で、どうなったかというと

  • 手元の環境では移行に2時間40分ほどかかった(「数分かかることがあります」とはいったい....)
  • 手元のPCには16GBほどメモリを積んでいるんだけど、途中、vmmemというプロセスが10GBほどメモリを握りこんで動作が非常に緩慢になる

....てな感じではあったもののどうにか終了。変換が終了したら、vmmemが握っていたメモリは無事解放された。

ちなみにこのvmmemというプロセス、後で調べてみたら、どうやらこれが「WSL2が使っているマネージドVM」な模様。

1. Xクライアントを動かせるようにする

変換が無事終わったので WSLのUbuntuを起動。

僕はWindows用XサーバのVcXsrvをホスト環境に入れていて、Linuxのほうがいろいろと都合がいいPHPなんかは、WSLからPhpStormなんかを立ち上げて読み書きしているんだが、日本語入力ができないと何かと不便なので、WSLのシェルスタートアップ時にインプットメソッドのfcitxを起動するようにしている。

と、起動すると、「ディスプレイに接続できない」だの、「dbus-launchが異常終了して初期化できない」だの、思ってたのと違う状況に。

いろいろググりあげた結果、次のようにすることで解決した。

  1. ディスプレイに接続できない件は、DISPLAY環境変数の設定をlocalhostからresolv.confのアドレスに変えるQiitaの記事を参考にして解決
  2. dbus-launchが異常終了する件は、StackExchangeに同様のお悩みを抱えた方からの質問を参照して解決

2. どうしてこうなった

後追いでどうしてこうなったのか調べてみることに。

「WSLはAPI変換方式からマネージドVM方式に変わる」という話は小耳にはさんだことはあったのだけど、それがどういった影響があるのかまでは気にしていなかったのでいまさらなんだけど、ASCII.jpに懇切丁寧な解説記事があるのを発見。

記事を参照すると「WSL用の仮想スイッチが追加されている」ということなのでタスクマネージャーを見てみると、確かにvEthernet(WSL)というのが追加されている。

Task_mgr_1
一方、WSL内部でifconfigしてみたところ、ネットワークアドレスは172.27.128.0/20のようだ。プリフィックス20とは広くとってんな、というのが正直な感想。

  $ ifconfig
  eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
          inet 172.27.136.3  netmask 255.255.240.0  broadcast 172.27.143.255
          inet6 fe80::215:5dff:fe7a:7ea1  prefixlen 64  scopeid 0x20<link>
          ether 00:15:5d:7a:7e:a1  txqueuelen 1000  (イーサネット)
          RX packets 2699  bytes 421846 (421.8 KB)
          RX errors 0  dropped 0  overruns 0  frame 0
          TX packets 102  bytes 7288 (7.2 KB)
          TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

  lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
          inet 127.0.0.1  netmask 255.0.0.0
          inet6 ::1  prefixlen 128  scopeid 0x10<host>
          loop  txqueuelen 1000  (ローカルループバック)
          RX packets 0  bytes 0 (0.0 B)
          RX errors 0  dropped 0  overruns 0  frame 0
          TX packets 0  bytes 0 (0.0 B)
          TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ただ、「再起動するとアドレスは変わるので一定にならない」そうなので、この値はあくまで参考値ということになる。

早い話、Windowsホスト環境とWSL内部はvEthernetのアドレスを接点にNATされている、ということのようなので、件のQiitaの記事で書かれている/etc/resolv.confのnameserverのアドレスを指定するやり方で問題ない、ということのようだ。

一方StackExchangeで紹介されているdbus-launchだが、DESCRIPTIONの冒頭には

dbus-launch コマンドは、シェルスクリプトから dbus デーモンのセッションバスインスタンスを開始するために使用されます。
通常は、ユーザーのログイン スクリプトから呼び出されます。デーモン自体とは異なり、dbus-launch は終了するので、
バックティックや $() コンストラクトを使用して dbus-launch から情報を読み取ることができます。

 

引数を指定しない場合、dbus-launch はセッションバスインスタンスを起動し、そのインスタンスのアドレスと PID を
標準出力に出力します。

....とある。WSL内で実際に実行してみると、シェル変数定義を二つ返す。

  $ dbus-launch
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-Xq7M2S9YAw,guid=f6f9e17a76a4f8db225fc4bd5ed2165b
DBUS_SESSION_BUS_PID=389

manpagesの記載によれば、Xセッションの開始時にこれらの変数定義がないと新しいセッションを開始するようになっていて、事前定義するなどでdbus-launchによる自動起動を回避できるようだ。

fcitxがdbusを使っているので、dbus-launchの起動方法を工夫することはできるんだろうけど。

3. ところで使用感は

ざっくりこんなところ。

  • DockerをWSL2バックエンドに変えたら、明らかに起動が速くなったうえ、ホスト環境へのパフォーマンス影響も体感的には相当改善された、気がする
  • 従来のLXSSカーネルモジュールでの動作と比べ、Ubuntu Shellの起動は明らかに遅くなった
  • メモリをもりもり食うようになった
    ※WSL2の起動で2GBほど、Dockerを加えると+1.8GB、これにコンテナが乗るとさらに増える、といった感じ

ところで、WSL2で使うことになったアドレス範囲を内部ネットワークですでに使っている場合、どうなるんだろう?

続きを読む "WSL2にした話" »

2020年1月 9日 (木)

CSRを楽に作る

0. CSR is 何

SSL証明書の署名要求(Certificate Signing Request)のこと。[出典]

仕事でSSL証明書の更新をやることになったんだけど、その時に必要なデータを作るのが微妙にめんどかった。

1. 一発作成できるようにしてみた

やることはおおむね以下のとおり。

  1. 秘密鍵の生成
  2. 秘密鍵をもとにしたCSRの作成
  3. CSRをしかるべき証明機関に送って署名してもらう
  4. 対になる秘密鍵と署名済み公開鍵(あれば中間証明書も)をサーバに仕込む

最後の「秘密鍵と署名済み公開鍵をサーバに仕込む」は、まぁ読んで字のごとくなんだが、opensslで秘密鍵とCSRを生成するのを年1回しかやらないと色々忘れるので、処理をシェルスクリプトに固めてみた。
ちなみに対象環境はWSLのUbuntu。

使い方は以下のとおり。
ソースを見てもらえばわかるけど、それぞれデフォルト値が設定されている。

create_csr.sh [-d domain] [-p passphrase] [-s subject] [-y year]
  -d domain     ファイル名にするドメイン名
  -p passphrase 秘密鍵生成に使うPEMパスフレーズ
  -s subject    証明書のDN
  -y year       発行年

こいつを実行することで、カレントディレクトリに発行年のディレクトリを作成して秘密鍵とCSRを作成、CSRの中身をクリップボードへ放り込む。

あとは、クリップボードの中身を証明機関のWeb画面にペーストすれば署名要求は完了、という算段になっている。

2. 改造について

改造するとしたら、2~6行目のデフォルト値の部分、最終行のクリップボードへ送る処理、あたりか。

特に最終行はOSごとに処理が異なるので、変更は必須じゃなかろうか。

2019年12月15日 (日)

俺氏、ついにWindowsでgo-oci8を使うことに成功する

0. 結果的にいろいろ理解不足だった

前回記事では進捗ダメです状態で終わっていたのだけど、あれからいろいろいじり倒してどうにか形にすることができた。

まず前回記事の最後にある

  > go get github.com/mattn/go-oci8
  # github.com/mattn/go-oci8
  In file included from GOPATH\src\github.com\mattn\go-oci8\cHelpers.go:3:0:
  ./oci8.go.h:1:17: fatal error: oci.h: No such file or directory
  compilation terminated.

について。これはoci8.pcのインクルードパスの書き方に問題があったようで、InstantClient側の階層を一つ下げるとともに、WindowsのパスセパレータであるバックスラッシュをUnix系OSで使われるスラッシュに置き換えることで事なきを得た。

  orasdk=C:/bin/instantclient_19_3/sdk
  gcc=C:/bin/TDM-GCC-64

  oralib=${orasdk}/lib/msvc
  orainclude=${orasdk}/include

  gcclib=${gcc}/lib
  gccinclude=${gcc}/include

  glib_genmarshal=glib-genmarshal
  gobject_query=gobject-query
  glib_mkenums=glib-mkenums

  Name: oci8
  Description: oci8 library
  Libs: -L${gcclib} -L${oralib} -loci
  Libs.private:
  Cflags: -I${orainclude} -I${gccinclude}
  Version: 19.3.0

1. 最終的にどうしたのか

どうやら、最初から以下のようにしておけばよかった、ということらしい。

  1. GCCをMinGW GCCの最新版にする
  2. MinGWと同じツールチェインで作られているGTK+由来のpkg-configを追加する
  3. oci8.pcをUnix形式のパスセパレータ表記で作成する

1-1. GCCをMinGW GCCの最新版にする

推奨品という触れ込みのTDM-GCCだが、上記のoci8.pcgo buildしてみると、

  C:\bin\instantclient_19_3\sdk\lib\msvc\oci.lib
  error adding symbols: File in wrong format
  collect2.exe: error: ld returned 1 exit status

と出る。

ググると同じところで躓いていた人がおり、スレッドを追っていくことで原因が「GCCのバージョンが古いこと」だということにようやく気が付いた。

なので、SourceForgeのMinGW-w64 - for 32 and 64 bit WindowsにあるMinGW-w64のインストーラを使ってMinGWのツールチェインをインストールした。
今回はversion 8.1.0を使い、フレーバーはインストーラのデフォルトと思しきPOSIX/sehにした。

1-2. MinGWと同じツールチェインで作られているGTK+由来のpkg-configを追加する

MinGWにはokg-configは含まれないので、前回記事で入れたgettext、glib、pkg-configをMinGWのインストール先に上書きで統合するだけ。

1-3. oci8.pcをUnix形式のパスセパレータ表記で作成する

パスセパレータについては前述のとおり変更済みなので、GCCを変更したことに対応させる。
最終的にoci8.pcはこうなった。

  orasdk=C:/bin/instantclient_19_3/sdk
  gcc="C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64"

  oralib=${orasdk}/lib/msvc
  orainclude=${orasdk}/include

  gcclib=${gcc}/lib
  gccinclude=${gcc}/include

  glib_genmarshal=glib-genmarshal
  gobject_query=gobject-query
  glib_mkenums=glib-mkenums

  Name: oci8
  Description: oci8 library
  Libs: -L${gcclib} -L${oralib} -loci
  Libs.private:
  Cflags: -I${orainclude} -I${gccinclude}
  Version: 19.3.0

この状態でgo installしてみると、特にエラーアウトプットはなし。どうやらいけたらしい。
Elwhjakuyaaahoa

で、動作確認をしてみる。
_example/dbms_outputは、発行したSQLの戻りに入っている文字列「hello」を表示するものなので、最終的なアウトプットに「hello」と出ていればいいはず。

  C:\Users\f97one\GOPATH\src\github.com\mattn\go-oci8\_example\dbms_output>set GO_OCI8_CONNECT_STRING=system/Orcl19cAdmin@//localhost:1521/ORCLCDB
  C:\Users\f97one\GOPATH\src\github.com\mattn\go-oci8\_example\dbms_output>go run -x main.go
  WORK=C:\Users\f97one\AppData\Local\Temp\go-build013517802
  mkdir -p $WORK\b001\
  cat >$WORK\b001\importcfg.link << 'EOF' # internal
  packagefile command-line-arguments=C:\Users\f97one\AppData\Local\go-build\58\5863c3505d965e6d20b9f8f592c519e220e5eed4b41183b13033d2e2374a1571-d
  packagefile database/sql=C:\Users\f97one\AppData\Local\go-build\62\628feb6160d48c5ea359bb61135be38aa5057fe7edbe4e99838bfb2c6089bbde-d
  packagefile fmt=c:\go\pkg\windows_amd64\fmt.a
  packagefile github.com/mattn/go-oci8=C:\Users\f97one\GOPATH\pkg\windows_amd64\github.com\mattn\go-oci8.a
  packagefile log=c:\go\pkg\windows_amd64\log.a
  packagefile os=c:\go\pkg\windows_amd64\os.a
  packagefile runtime=c:\go\pkg\windows_amd64\runtime.a
  packagefile context=c:\go\pkg\windows_amd64\context.a
  packagefile database/sql/driver=C:\Users\f97one\AppData\Local\go-build\bb\bbc0505de003812bb8e208b6f9c39c7ee40a4e3ade95c0d9d2db378042112a86-d
  packagefile errors=c:\go\pkg\windows_amd64\errors.a
  packagefile io=c:\go\pkg\windows_amd64\io.a
  packagefile reflect=c:\go\pkg\windows_amd64\reflect.a
  packagefile sort=c:\go\pkg\windows_amd64\sort.a
  packagefile strconv=c:\go\pkg\windows_amd64\strconv.a
  packagefile sync=c:\go\pkg\windows_amd64\sync.a
  packagefile sync/atomic=c:\go\pkg\windows_amd64\sync\atomic.a
  packagefile time=c:\go\pkg\windows_amd64\time.a
  packagefile unicode=c:\go\pkg\windows_amd64\unicode.a
  packagefile unicode/utf8=c:\go\pkg\windows_amd64\unicode\utf8.a
  packagefile internal/fmtsort=c:\go\pkg\windows_amd64\internal\fmtsort.a
  packagefile math=c:\go\pkg\windows_amd64\math.a
  packagefile bytes=c:\go\pkg\windows_amd64\bytes.a
  packagefile encoding/binary=c:\go\pkg\windows_amd64\encoding\binary.a
  packagefile io/ioutil=c:\go\pkg\windows_amd64\io\ioutil.a
  packagefile regexp=C:\Users\f97one\AppData\Local\go-build\d2\d2c97385147b6b2df852f8314ea0bc365ea5fd428c22cc28a7751caff46481e2-d
  packagefile strings=c:\go\pkg\windows_amd64\strings.a
  packagefile runtime/cgo=C:\Users\f97one\AppData\Local\go-build\05\050b0c52184a06b9e406b4908e746f8690cbeab9c2d8c629ec5358b2648f5d6f-d
  packagefile syscall=c:\go\pkg\windows_amd64\syscall.a
  packagefile internal/oserror=c:\go\pkg\windows_amd64\internal\oserror.a
  packagefile internal/poll=c:\go\pkg\windows_amd64\internal\poll.a
  packagefile internal/syscall/windows=c:\go\pkg\windows_amd64\internal\syscall\windows.a
  packagefile internal/testlog=c:\go\pkg\windows_amd64\internal\testlog.a
  packagefile unicode/utf16=c:\go\pkg\windows_amd64\unicode\utf16.a
  packagefile internal/bytealg=c:\go\pkg\windows_amd64\internal\bytealg.a
  packagefile internal/cpu=c:\go\pkg\windows_amd64\internal\cpu.a
  packagefile runtime/internal/atomic=c:\go\pkg\windows_amd64\runtime\internal\atomic.a
  packagefile runtime/internal/math=c:\go\pkg\windows_amd64\runtime\internal\math.a
  packagefile runtime/internal/sys=c:\go\pkg\windows_amd64\runtime\internal\sys.a
  packagefile internal/reflectlite=c:\go\pkg\windows_amd64\internal\reflectlite.a
  packagefile math/bits=c:\go\pkg\windows_amd64\math\bits.a
  packagefile internal/race=c:\go\pkg\windows_amd64\internal\race.a
  packagefile internal/syscall/windows/registry=c:\go\pkg\windows_amd64\internal\syscall\windows\registry.a
  packagefile path/filepath=c:\go\pkg\windows_amd64\path\filepath.a
  packagefile regexp/syntax=C:\Users\f97one\AppData\Local\go-build\09\09ed04a320a2025b1e0a177d0508fba26180bcc7e9a93f5b6b9a0215a3250c5a-d
  packagefile internal/syscall/windows/sysdll=c:\go\pkg\windows_amd64\internal\syscall\windows\sysdll.a
  EOF
  mkdir -p $WORK\b001\exe\
  cd .
  "c:\\go\\pkg\\tool\\windows_amd64\\link.exe" -o "C:\\Users\\f97one\\AppData\\Local\\Temp\\go-build013517802\\b001\\exe\\main.exe" -importcfg "C:\\Users\\f97one\\AppData\\Local\\Temp\\go-build013517802\\b001\\importcfg.link" -s -w -buildmode=exe -buildid=ZWzZXxPk1jGh5zBAmzMZ/JNrpGUoogY-8JjSab9MF/eSW2eCfLhSZIeYr8x4zF/ZWzZXxPk1jGh5zBAmzMZ -extld=gcc "C:\\Users\\f97one\\AppData\\Local\\go-build\\58\\5863c3505d965e6d20b9f8f592c519e220e5eed4b41183b13033d2e2374a1571-d"
  $WORK\b001\exe\main.exe
  hello

  C:\Users\f97one\GOPATH\src\github.com\mattn\go-oci8\_example\dbms_output>

今度は大丈夫そうである。

2. 終わりに

蓋を開けてみれば、GCCさえちゃんとしていれば何の苦労もなかった、ということなんだが、MSYS2のpacmanが挙動不審になるのを皮切りに、いろいろ大周りをする羽目になった。

2019年12月14日 (土)

Windowsでmatn/go-oci8を使おうとしてとても苦労している話

0. 唐突にOracle Databaseを使おうと思い立った

Oracle Databaseを使ったシステムなど、お仕事くらいでしか使うことはなかったんだけど、Oracle Cloud Free Tierとして使えるDBのPaaSがOracle Databaseだけ、というので、かなり仕方なく使う、というネガティブな話だったりする。

Javaや.NETには公式のデータベースドライバが出ているので、それらを使えば簡単にDBを利用できるけど、せっかくなので今回はGoでやってみることにした。

なお、結論から書くとこの話、実現できてないorz

1. 環境

ビルドには以下が必要。

  • C/C++コンパイラ
  • pkg-config
  • プラットフォームとバージョンに応じたOracle InstantClient

このほか、当然のことながらGitやGoが必要。

1-1. MSYS2

僕のWindows PC(Windows 10 pro version 1909)にはSphinxでPDFをビルドするため、MSYS由来のGNU Makeとshが入っていたので、GCCを入れるためpacmanを起動。
しかしながら、なぜか何もフィードバックを出さずpacmanが途中で終了してしまい、パッケージのインストールもアップデートもできずハマる。

おかしい、version 1809のころはふつうにpacmanが動いていたはずなのに。

これでは何もできないので、MSYS2はあきらめることに。

1-2. Cygwin

ならば、ということでMSYS2をアンインストールしてCygwin x64を入れてみた。

Baseパッケージグループのほか、makeやGCCをCygwin Installerで一とおりインストールし、C:\cygwin64\binなどをWindowsのPath環境変数に追加していった。

Cygwin shellではなくDOS窓からgo get github.com/mattn/go-oci8とやったところ、

  # runtime/cgo
  gcc_libinit_windows.c: 関数 ‘x_cgo_sys_thread_create’ 内:
  gcc_libinit_windows.c:57:12: エラー: implicit declaration of function ‘_beginthread’; did you mean ‘OpenThread’? [-Werror=implicit-function-declaration]
    thandle = _beginthread(func, 0, arg);
              ^~~~~~~~~~~~
              OpenThread
  cc1: all warnings being treated as errors
  go: failed to remove work dir: GetFileInformationByHandle C:\cygwin64\tmp\go-build601027150\NUL: Incorrect function.

と出てビルドできず。後でググると本体のGitHub WikiInstallFromSource

Go does not support the Cygwin toolchain.

などど書かれていた。なん....だと....?

1-3. WSL

最近のエディションにはWSL(Windows Subsystem for Linux)という、読んで字のごとくLinux互換環境を提供するサブシステムが標準搭載されている。デーモンを常駐させられない以外はほぼLinuxそのままなので、こいつで頑張ってみることに。

僕は普段UbuntuのWSLを使っているけど、GCCもpkg-configもapt installで導入できるのでお手軽だ。

ということでapt installでGCCやらpkg-configやらをインストールしてgo getしてみる。
結果、エラー表示は出ず。

いけた、のか? ということで付属のexampleで動作確認。

  $ cd $GOPATH/src/github.com/mattn/go-oci8/_example/nls
  $ GO_OCI8_CONNECT_STRING=system/Orcl19cAdmin@//localhost:1521/ORCLCDB go run main.go
  ORA-12571: TNS:packet writer failure

パケット到達不能、だと....? まぁ、Oracle Databaseは親環境のDockerで動かしているとはいえ、WSLからDockerを制御できているので、親環境とは通信できているはずだが。

てなわけで、この方法もダメということに。

1-4. TDM-GCC

Goの公式としてはTDM-GCCを推奨しているようなので、Cygwin GCCをアンインストールしてこちらに切り替えてみた。

パッケージマネージャは付属していないので、pkg-configを自力でセットアップしなければならない。やり方自体はStackOverflowの記事を参考にやってみた。

一応、直リンクを置いておく。

準備自体はGistを残してくれている方がいたので、それを使わせてもらうことに。

  > go get github.com/mattn/go-oci8
  # pkg-config --cflags  -- oci8
  pkg-config: exit status 3221225595

3221225595をWindowsの電卓に通すと0xC000007Bになるのだが、pkg-configが正常起動できていない、ということのようだ。どうやらABIが違うようなので、win64ではなくwin32に変えることで正常起動するようになった。

で、再挑戦。

  > go get github.com/mattn/go-oci8
  # github.com/mattn/go-oci8
  In file included from GOPATH\src\github.com\mattn\go-oci8\cHelpers.go:3:0:
  ./oci8.go.h:1:17: fatal error: oci.h: No such file or directory
  compilation terminated.

....pkg-configがインクルードパスを正常に処理できていないようだ。もちろん、oci.hの場所は-Iオプションの行で指定しているんだが。

おわりに

最後のTDM-GCCパターンではあと一歩なような気もする。

そんな気はするんだが、MySQLやPostgreSQLのドライバだったり、GoではなくJavaを選択していた場合だと、もっと簡単にデータアクセスを実装できていたであろう、と考えると、「なぜ僕はこんな苦行を....?」などと考えてしまう。

2019年7月20日 (土)

続々:BSoDとの戦いに挑む

収束した....のか?

前回前々回のポストからいくつかやってみた結果の結論から言うと、Version 1903をインストールしたら収まった。ような気がする。

それまでにやったこと

ざっくり書くとこんな感じ。

  1. 余計な仮想スイッチの削除
  2. NICのドライバ更新
  3. Windows 10 Version 1903 (Windows 10 May 2019 Update) のインストール

1. 余計な仮想スイッチの削除

OSはPro版なのでHyper-Vが使えるんだけど、Version 1709から「既定のスイッチ(Default Switch)」と呼ばれる仮想スイッチが自動で作成されるようになった。

既定のスイッチについてはQiitaに解説記事が投稿されているのでそちらを参照いただくとして、過去Hyper-Vゲストにインターネットアクセスさせるために仮想スイッチを作っていたことがあり、そいつと機能的に噛んでいるのでは?ということで既定のスイッチだけ残して残りは削除することに。

ちなみにこれ、Hyper-Vの役割をセットアップしていないと削除できないので、Hyper-Vをセットアップして既定のスイッチ以外を削除して再起動。
これでしばらく様子をみることにしたが、一日置いてBSoD発症。

2. NICのドライバ更新

デバイスマネージャーでNIC(有線、無線とも)を見てみると、Windows Update経由でインストールされたものが使用されていた。

そういえば昔(10年以上前の話だが)、両面自動印刷機能とかが付いたHPのカラーインクジェットプリンタをWindows Updateのドライバで動かそうとしたら、片面印刷だけ、かつカラー不可という非常にイケてない状況になったことがあったので、IntelからNICのドライバをダウンロードしてセットアップ。
同様に様子を見ていたら、作業の3日後にBSoD発症。

3. Windows 10 Version 1903 のインストール

バージョン情報をみると、Version 1903公開から2か月以上たっていたにもかかわらずVersion 1803のままだった。たぶん、1903をダウンロードできるだけのまとまった稼働時間を確保していなかったのだろう。

ということで、更新アシスタントからVersion 1903を手動セットアップすることに。

結果、Intel製NICドライバは見事Windows Update版で上書きされてしまったが、実のところVersion 1903をセットアップして以降BSoDは発症していない。こっちの記事でDocker for Windowsを使っていても、である。

はっきりしないうちに収束した感があるので、モヤモヤするものが若干あるけれど。

2019年6月23日 (日)

続:BSoDとの戦いに挑む

ネイティブモジュールのデバッグに挑む

先日のポストでToDoにしていた、デバッガのセットアップとかをやってみた。

いまどきのデバッガ

Debugging Tools for Windows というやつを使うんだが、こいつにはMicrosoft Store版があって、最新のWindows 10の場合そちらのほうがより近代的なんだそうな。

Windbg Preview in Microsoft Store

ストアアプリなので、導入自体はいたって簡単。ストアからアプリを入れたら、アクセスしやすくするためスタートメニューにピン止めしておく。

一方、ダンプサイズの拡張については、最近のWindowsはやらなくてもそれなりのサイズを確保してくれるらしい。設定自体は以前と同じシステムのプロパティの中の「起動と回復」の中にある。

Boot_and_recovery

デフォルト値が「自動メモリダンプ」になっていて、メモリを16GB搭載しているこのPCでは、だいたい1GB~1.5GB程度のダンプを確保してくれるようになっている。
昔のデフォルト値は「最小メモリダンプ(256KB)」だったので、ダンプから自力でどうにかしようと考えているような人にはいい時代になった、と言える(?)

実際にデバッガにかけてみる

実のところ、よく発生しているBSoD 2種が先日の記事を書いた後で運よく(?)発生したので、ダンプを確保して分析にかけてみることにした。
WinDbgを起動して、確保したダンプを読み込ませると、自動的に簡易分析が始まる。デバッグシンボルの取得は勝手にやってくれるようだ。

0xd1_simple_analysis

画面中の !analyze -v のリンクを押すと分析が始まる。
以下は DRIVER_IRQL_NOT_LESS_OR_EQUAL で BSoD になったやつを分析したときの出力だけど、長いので途中省略。 vmswitch というモジュールがトリガーになったようだ。

0: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

 

DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high.  This is usually
caused by drivers using improper addresses.
If kernel debugger is available get stack backtrace.
Arguments:
Arg1: 0000000000000548, memory referenced
Arg2: 0000000000000002, IRQL
Arg3: 0000000000000000, value 0 = read operation, 1 = write operation
Arg4: fffff808c961972b, address which referenced memory

 

Debugging Details:
------------------
  :
(中略)
  :
FOLLOWUP_IP: 
vmswitch!VmsQueueGroupIsRestrictedQueue+7
fffff808`c961972b 8b9048050000    mov     edx,dword ptr [rax+548h]

 

FAULT_INSTR_CODE:  548908b
SYMBOL_STACK_INDEX:  3
SYMBOL_NAME:  vmswitch!VmsQueueGroupIsRestrictedQueue+7
FOLLOWUP_NAME:  MachineOwner
MODULE_NAME: vmswitch
IMAGE_NAME:  vmswitch.sys
DEBUG_FLR_IMAGE_TIMESTAMP:  62acf328
STACK_COMMAND:  .thread ; .cxr ; kb
BUCKET_ID_FUNC_OFFSET:  7
FAILURE_BUCKET_ID:  AV_vmswitch!VmsQueueGroupIsRestrictedQueue
BUCKET_ID:  AV_vmswitch!VmsQueueGroupIsRestrictedQueue
PRIMARY_PROBLEM_CLASS:  AV_vmswitch!VmsQueueGroupIsRestrictedQueue
  :

そして、もう一つ。 KERNEL_SECURITY_CHECK_FAILURE で BSoD になったやつを分析してみる。

Loading Dump File [C:\work\memdumps\0x139_vmswitch-sys_20190622-03.DMP]
Kernel Bitmap Dump File: Kernel address space is available, User address space may not be available.

 

 

************* Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       srv*
Symbol search path is: srv*
Executable search path is: 
Windows 10 Kernel Version 17134 MP (4 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 17134.1.amd64fre.rs4_release.180410-1804
Machine Name:
Kernel base = 0xfffff803`254b0000 PsLoadedModuleList = 0xfffff803`2585d170
Debug session time: Sat Jun 22 22:09:48.984 2019 (UTC + 9:00)
System Uptime: 0 days 5:39:39.842
Loading Kernel Symbols
.........................................Page 20008bef5 too large to be in the dump file.
Page 2000aadf4 too large to be in the dump file.
......................
................................................................
................................................................
...............................
Loading User Symbols

 

Loading unloaded module list
..............
For analysis of this file, run !analyze -v
nt!KeBugCheckEx:
fffff803`2565aab0 48894c2408      mov     qword ptr [rsp+8],rcx ss:0018:ffffda05`86612940=0000000000000139
2: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

 

KERNEL_SECURITY_CHECK_FAILURE (139)
A kernel component has corrupted a critical data structure.  The corruption
could potentially allow a malicious user to gain control of this machine.
Arguments:
Arg1: 0000000000000003, A LIST_ENTRY has been corrupted (i.e. double remove).
Arg2: ffffda0586612c60, Address of the trap frame for the exception that caused the bugcheck
Arg3: ffffda0586612bb8, Address of the exception record for the exception that caused the bugcheck
Arg4: 0000000000000000, Reserved

 

Debugging Details:
------------------
  :
(中略)
  :
FOLLOWUP_IP: 
vmswitch!VmsQsUpdatePerProcessorPacketStats+2c3
fffff80b`e4a67be3 cd29            int     29h

 

FAULT_INSTR_CODE:  8d4829cd
SYMBOL_STACK_INDEX:  4
SYMBOL_NAME:  vmswitch!VmsQsUpdatePerProcessorPacketStats+2c3
FOLLOWUP_NAME:  MachineOwner
MODULE_NAME: vmswitch
IMAGE_NAME:  vmswitch.sys
DEBUG_FLR_IMAGE_TIMESTAMP:  62acf328
STACK_COMMAND:  .thread ; .cxr ; kb
BUCKET_ID_FUNC_OFFSET:  2c3
FAILURE_BUCKET_ID:  0x139_3_CORRUPT_LIST_ENTRY_vmswitch!VmsQsUpdatePerProcessorPacketStats
BUCKET_ID:  0x139_3_CORRUPT_LIST_ENTRY_vmswitch!VmsQsUpdatePerProcessorPacketStats
PRIMARY_PROBLEM_CLASS:  0x139_3_CORRUPT_LIST_ENTRY_vmswitch!VmsQsUpdatePerProcessorPacketStats

おや? こちらも vmswitch がトリガーになっているようだ。

問題になっているモジュールが特定できたので、次はワークアラウンドの検索かな....。

2019年6月21日 (金)

BSoDとの戦いに挑む

ここ最近ひどい

僕が普段使いしている Panasonic CF-B11 というノート PC なんだけど、ここ最近不定期に BSoD を出してくる。
どうにかしなきゃね、ということで、調べてみることに。

イベントログを読む

Windows という OS はぎりぎりまできっちりイベントログを収集していて、それは BSoD による強制再起動も例外ではない。ということは割と知られていることなので、とりあえず直近の2か月ほどを抜いてみる。

BSoD イベントは、 System イベントログ内に BugCheck というソース名で記録されるので、 Windows PowerShell でとりあえずヘッドラインだけでも出してみる。

PS > Get-EventLog -LogName System -After "2019/05/01" | Where-Object {$_.Source -eq "BugCheck"}

   Index Time          EntryType   Source                 InstanceID Message                                                                            
   ----- ----          ---------   ------                 ---------- -------                                                                            
  157766 6 20 06:47    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  156383 6 17 21:48    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  151168 6 08 16:26    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  148570 6 08 15:11    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  146691 6 05 20:38    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  145460 6 03 22:35    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  144162 6 02 20:54    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  137197 6 01 22:18    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  136141 6 01 07:49    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  133441 5 26 19:51    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  133303 5 26 13:27    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  132988 5 25 21:32    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  132631 5 25 19:19    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  131648 5 24 23:02    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  130682 5 22 22:24    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  129735 5 20 21:04    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  129301 5 19 15:18    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  128834 5 19 11:44    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  128416 5 18 22:42    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  126350 5 13 22:47    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  125399 5 12 10:24    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  125194 5 11 23:39    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  123956 5 08 13:52    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  121016 5 02 23:33    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  120450 5 02 15:58    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...
  119397 5 01 19:09    Error       BugCheck               1073742825 ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DL...

あー、このアウトプットではだめだ、ということで、 Format-List に通してみたところ、大半がこんな感じ。

Index              : 120450
EntryType          : Error
InstanceId         : 1073742825
Message            : ソース 'BugCheck' のイベント ID '1073742825' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DLL ファイルがローカル コンピューターに存在しない可能性があります。または、これらのデータへのアクセス
                     許可がユーザーに与えられていない可能性があります。次の情報はイベントの一部です:'0x00000139 (0x0000000000000003, 0xfffff801f3072950, 0xfffff801f30728a8, 0x0000000000000000
                     )', 'C:\WINDOWS\MEMORY.DMP', 'b537a1cf-30ea-4911-be63-13624e70de94'
Category           : (0)
CategoryNumber     : 0
ReplacementStrings : {0x00000139 (0x0000000000000003, 0xfffff801f3072950, 0xfffff801f30728a8, 0x0000000000000000), C:\WINDOWS\MEMORY.DMP, b537a1cf-30ea-
                     4911-be63-13624e70de94}
Source             : BugCheck
TimeGenerated      : 2019/05/02 15:58:00
TimeWritten        : 2019/05/02 15:58:00
UserName           : 

ReplacementStrings 行をみると、バグチェックコードが 0x139 だとわかった。先頭の16進数がそれだ。
MSDN の Bug Check Code Reference によれば、

カーネルが重要なデータ構造の破損を検知した
んだそうな。[出展]

加えて、先頭から2番目の16進数は「破損のタイプ」だそう。前述の MSDN の記事では、

A LIST_ENTRY was corrupted (for example, a double remove). For more information, see the following Cause section.

LIST_ENTRY というのは、リスト構造のデータを扱う構造体のことのようだ。

むぅ、構造体そのものではなくて、そいつを操作している処理を特定しないといけないようだ。ここから先の追跡は、デバッガ使ってダンプを眺めてみるしかなさそうだけど、デバッガって Visual Studio のどのコンポーネントに入ってるんだろう?

次の ToDo

  1. デバッガのセットアップ
  2. ダンプの取得サイズを1段階上げる設定に変える

くらいかな....?

2019年4月21日 (日)

MySQL素人がWindows版で3rd partyユーティリティからの接続を使えるようにした話

終わってみればどうということはないけれど

 

正解に行きつくまで、正直なところ相当苦労した。いや、ぼくの MySQL 力がしょぼいせいだけど。

 

何が問題だったのか

 

かいつまんで書くとこんなところ。

 

  • 開発にも使っている自分の Windows PC に、 MySQL Community Edition 8.0 をインストール
  • 起動モードは Windows Service に設定 (Window なので)
  • 同時にインストールできる MySQL Workbench から接続に行くと普通に使える(まぁ、当たり前)
  • 普段は JetBrains DataGrip を使っているので、 DataGrip からローカルホストの MySQL に接続しようとすると「タイムゾーンがおかしい」といって接続できない

 

やったことの備忘録

 

大きくわけて二つ。

 

  1. タイムゾーン設定のインポート
  2. 起動時に参照されるタイムゾーン設定の作成

 

1. タイムゾーン設定のインポート

 

「そう言えば、タイムゾーンって my.cnf とかに書くやつじゃなかったっけ?」というわけで、そのあたりをググってみたところ、

 

Windowsの場合はOSにタイムゾーンの設定が無いため、タイムゾーンのファイルをダウンロードする必要があります。

 

などという記述を発見。
「ええ?そうなん?」と思いつつも、公式の MySQL :: Time zone description tables から、 MySQL 5.7以上むけの POSIX 標準 SQL ファイルをダウンロードして実行。

 

これでタイムゾーンの管理情報は作成できたので、起動してみるがダメ。

 

2. 起動時に参照されるタイムゾーン設定の作成

 

ここでどんなタイムゾーン設定が有効になっているのかを調べてみる。

 

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | |
| time_zone | SYSTEM |
+------------------+--------+
2 rows in set (0.01 sec)

 

これはどういうことなのか? と再度調べてみたところ、

 

 

変数名 説明
system_time_zone システムのタイムゾーンで、起動時に TZ 環境変数を参照して決定したあとは、変更されることはない
time_zone サーバのカレントタイムゾーンで、権限があれば後から変更できる。
初期値は SYSTEM で、 system_time_zone と同じであることを表す

 

....とのことのようだ。(出展 : http://download.nust.na/pub6/mysql/doc/refman/5.1/ja/time-zone-support.html)

 

なるほど、 my.cnf を編集しなくても環境変数定義で大丈夫なのか。ということで、オフセット値を設定してみることに。
管理者権限のあるDOS窓を起動して、以下を投入。 MySQL はサービス稼働なので、システム環境変数として登録した。

 

> setx /m TZ +09:00

 

この状態で MySQL を再起動して、再びタイムゾーン設定を見てみると、

 

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | +09 |
| time_zone | SYSTEM |
+------------------+--------+
2 rows in set (0.01 sec)

 

....ということで、無事タイムゾーンが日本に設定されたようだ。

 

この状態で、再び GataGrip から接続を試みると、無事接続できた。

2018年7月20日 (金)

Sphinxの環境を整える

この記事の目標

  • Sphinxの編集環境を作る
  • こぎれいなPDFを出力できる環境をWindowsで作る

Sphinx is 何


SphinxはPythonで書かれたドキュメントビルダで、reStructuredTextというマークアップ言語で書かれたソースをこぎれいなHTMLなんかに変換してくれる優れもの。

Sphinxのインストール


詳しくは公式のSphinxのインストール参照。

以下、かいつまんで書く。

  1. Pythonをインストール、デフォルトでよいが、公式ではPython 3.xを推奨している模様
  2. PIPをインストール
  3. pip install -U Sphinxを実行


編集には、Visual Studio CodeとreStructuredText拡張を使っているが、UTF-8が扱えれば使い慣れたエディタで大丈夫。

こぎれいなPDFをWindowsで作る


実はここがこの記事のメイン。


とりあえず、自分で試したWindowsとLinux(Ubuntu)で必要だったパッケージについて、ざっくりまとめた。

ビルダ html epub latex latexpdf
Windows
要TeX Live

要TeX Live, GNU Make, sh
Linux
要TeX Live

要TeX Live


この表のとおり、SphinxでこぎれいなPDFを作るにはTeXの力を借りる必要があるんだが、これにはTeX Liveというパッケージを使うのが一番簡単だ。


インストーラはInstalling TeX Live over the Internetで取得できる。

Windowsの場合、ネットインストール型のインストーラを使うのがお手軽だが、時間はとてもかかる(2時間くらい?)ことを覚悟したほうがいい。

とはいえ、待っているだけで基本終了するので、特に難しいところはないはず。


また、Sphinxのlatexpdfビルダは、WindowsのDOS窓では処理ができない動きをするので、UNIX由来のツールであるGNU Makeとshを入れておく必要がある。

これにはMSYS2を使うことにした。


QiitaにMSYS2 による gcc 開発環境の構築という記事を投稿している方がいるので、そちらを参考にmakeだけを入れる。

入れたら、C:\msys64\usr\binをパスに追加しておくこと。


ここまでできれば、Sphinxのドキュメントプロジェクトのあるディレクトリでmake.exe latexpdfとやればこぎれいなPDFが出力できていることだろう。


なお、「Sphinxのlatexpdfビルダは、WindowsのDOS窓では処理ができない動きをする」件、一応Issueにも挙がっているようで、日本のメーリングリストでも話題になっているんだけど、なかなかfixしないよなぁ....。


2023年12月
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            

最近のトラックバック

無料ブログはココログ