Pythonのsubprocessモジュールの使用 [misc]
その際、OS のコマンドの実行に subprocess モジュールのどの関数を使用すべきかを理解するまでに時間を要したため、備忘録としてまとめてみた。
(Python のバージョン: 3.9.2)
1. 使用する関数の判断方法
(1) コマンドの実行結果を実行時に値として取得する場合
subprocess.Popen() を使用する。
【サンプルコード-1】
#!/usr/bin/python import subprocess cmd = 'ls -1 /var/log/clamav' print("# cmd:", cmd) proc = subprocess.Popen(cmd, shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print("# proc.stdout:") for i in proc.stdout: print(i, end='') print("# proc.stderr:") for i in proc.stderr: print(i, end='') proc.wait() print("# proc.wait(); proc.returncode:", proc.returncode)
・コマンドの終了を待たず、実行結果を値として取得する。
・Popen.wait() によりコマンドの終了を待つ。
Popen.wait() を Popen.communicate() に変更しても同じ結果が得られる。
・コマンドの終了後に終了ステータスを値として取得する。
(2) 上記以外の場合
(a) subprocess.run() の使用を検討する。
【サンプルコード-2】
#!/usr/bin/python import subprocess cmd = 'which xz' print("# cmd:", cmd) proc = subprocess.run(cmd, shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print("# proc.returncode:", proc.returncode) if proc.returncode == 0: print("# proc.stdout:", proc.stdout.rstrip('\n')) else: print("# proc.stderr:", proc.stderr.rstrip('\n'))
・コマンドの終了後に終了ステータスと実行結果を値として取得する。
【サンプルコード-3】
#!/usr/bin/python import subprocess cmd = 'which xz' print("# cmd:", cmd) proc = subprocess.run(cmd, shell=True, text=True) print("# proc.returncode:", proc.returncode)
・終了ステータスのみを値として取得する。
・コマンド実行時の出力の有無は、コマンドのリダイレクトの設定による。
出力なしとする場合には、'cmd >/dev/null 2>&1' のように実行する。
(b) 終了ステータスのみが必要な場合は、subprocess.call() の使用も検討する。
【サンプルコード-4】
#!/usr/bin/python import subprocess cmd = 'which xz >/dev/null 2>&1' print("# cmd:", cmd) status = subprocess.call(cmd, shell=True) print("# status:", status)
・終了ステータスを値として取得する。
・コマンド実行時の出力なし。
コマンド実行時の出力の有無は、コマンドのリダイレクトの設定による。
udevへのストレージに関するルールの追加 [Linux]
1. 要件
指定したデバイスへのシンボリック・リンク(パス名を固定)を /dev に作成する。
対象とするデバイスは、下記の通りである。
また、ルールは /etc/udev/rules.d/60-persistent-strage.rules に設定する。
(1) 2 個のバードディスクの一方にインストールされている Windows のパーティション
・/dev/part-win-1
・/dev/part-win-2
(2) SATA1、STAT2 に接続されているハードディスク
・/dev/ata-disk-1
・/dev/ata-disk-2
2. 作成したルール
(1) Windows のパーティションへのシンポリック・リンクの作成
(a) /dev/sda[12] を使用の場合
# NTFS partitions SUBSYSTEM=="block", ENV{ID_BUS}=="ata", ENV{ID_FS_TYPE}=="ntfs", \ SYMLINK+="part-win-%n"
(b) /dev/sda{1+x,2+x} を使用の場合
# NTFS partitions SUBSYSTEM=="block", ENV{ID_BUS}=="ata", ENV{ID_FS_TYPE}=="ntfs", \ PROGRAM="/bin/sh -c 'echo $((%n-x))'", SYMLINK+="part-win-%c"
・実際には一行で設定する。
・%n: デバイスの番号
・%c: PROGRAM で指定したコマンドの標準出力
(2) SATA1、STAT2 に接続されているハードディスクへのシンボリック・リンクの作成
# pci-0000:00:1f.2-ata-1.0 SUBSYSTEM=="block", ENV{ID_BUS}=="ata", ENV{DEVTYPE}=="disk", \ ENV{ID_PATH}=="pci-0000:00:1f.2-ata-1.0", SYMLINK+="ata-disk-1" # pci-0000_00_1f_2-ata-1.1 SUBSYSTEM=="block", ENV{ID_BUS}=="ata", ENV{DEVTYPE}=="disk", \ ENV{ID_PATH}=="pci-0000:00:1f.2-ata-1.1", SYMLINK+="ata-disk-2"
または
# pci-0000:00:1f.2-ata-1.0, pci-0000_00_1f_2-ata-1.1 SUBSYSTEM=="block", ENV{ID_BUS}=="ata", ENV{DEVTYPE}=="disk", \ ENV{ID_PATH}=="pci-0000:00:1f.2-ata-1.?", \ PROGRAM="/bin/sh -c \"echo $((`echo %E{ID_PATH} | sed 's/.*\.//'` +1))\"", \ SYMLINK+="ata-disk-%c"
・実際には一行で設定する。
・%E{ID_PATH}: ID_PATH の値
・同様のシンボリック・リンクが /dev/disk/by-path に存在する。
/dev/disk/by-path/pci-0000:00:1f.2-ata-1.0
/dev/disk/by-path/pci-0000:00:1f.2-ata-1.1
3. 備考
(1) ルールで指定できる項目の確認
% udevadm info --query=all --name=<dev-path>
clamdscanの使用方法に関するメモ [Linux]
以下は、clamdscan を使いやすくすることを目的としたメモ(備忘録)である。
(clamdscan のバージョン: 0.103.6)
1. スキャンしたファイルの表示
(1) -i オプションを指定せず、-z オプションを指定
下記の情報が追加表示される。 ・ウイルスが発見されなかったファイルのパス名 ただし、表示の対象はコマンドラインで直接指定されたファイルのみである。
(補足)
・-z を指定しないと表示されない。
-z: ウイルスが発見された後もスキャンを継続
・-i を指定の場合には、上記の追加表示は実施されない。
2. 再帰的なスキャンが実施されることの確認
対象がディレクトリの場合には、再帰的にスキャンが実施される。
明確な説明がないため、テストの実行結果から判断した。
(1) 階層の深さの制限
・設定ファイルの MaxDirectoryRecursion で指定する。
・設定値に関する詳細な説明資料はない。
(a) -z オプションを指定しないと必要な情報が出力されない。
(b) 設定値に誤りがある場合、エラーメッセージが出力される。
ERROR: Incorrect argument format for option MaxDirectoryRecursion ERROR: Can't parse clamd configuration file /tmp/clamd.conf (終了ステータスは 2 となる。)
(c) 設定値を超える深さにファイルが存在する場合、ワーニングが出力される。
WARNING: Directory recursion limit reached (終了ステータスは 2 となる。)
(d) 実行結果からの判断
・設定できる値は 0 以上である。 ・n(>=1) の場合: 指定ディレクトリの n 階層下のディレクトリまでが対象 指定ディレクトリ内の全ファイル(ディレクトリを含)が対象 指定ディレクトリ内のサブディレクトリは、指定された階層までが対象 ・0 の場合: 無制限となっているように思われる。 少なくとも、指定ディレクトリのみに限定するようにはならない。
(2) 再帰的なスキャンが実施されていることの証明
・サブディレクトリ内のテスト用ウイルスを見つけている。
(eicar.zip は、ウイルス検索のテストファイルである。)
・サブディレクトリ内の除外パスを除外している。
# clamdscan -z --stdout /work /work/backup: Excluded /work/lost+found: Excluded /work/linux/grub2/super_grub2_disk_hybrid_2.04s1.iso: Excluded /work/test/cache: Excluded /work/test/xxx.iso: Excluded /work/test/x1/x2/eicar.zip: Win.Test.EICAR_HDB-1 FOUND ----------- SCAN SUMMARY ----------- Infected files: 1 Time: 3.750 sec (0 m 2 s) ...
3. 一時的に設定を変更しての実行
別の設定ファイルを使用することにより、対応可能である。
(例) -- 除外パスの追加
・元の設定ファイルをコピーし、別の設定ファイルを作成
・上記で作成した設定ファイルに、除外パス(ExcludePath) を追加
・clamdscan の --config-file オプションで上記で作成した設定ファイルを指定
(補足)
上記で --config-file を使用した clamdscan にのみ追加設定が適用される。
--config-file を使用しない clamdscan には元の設定が適用される。
(ExcludePath、MaxDirectoryRecursion について動作を確認)
4. 効果が不明のオプション
(1) -v オプション
'be verbose' とのみ説明されており、効果が不明である。
また、-v の指定の有無による実行結果の違いを見つけられない。
Windowsのパーティションのマウント・エラーへの対応 [Linux]
autofs で Windows の NTFS パーティションをマウントできないことがある。
/etc/auto.misc の設定は、下記の通りである。
win_1 -fstype=ntfs,locale=ja_JP.eucJP,umask=022,ro /dev/sda1 win_2 -fstype=ntfs,locale=ja_JP.eucJP,umask=022 /dev/sda2
(補足)
Linux と Windows をマルチブートしている環境である。
2. 原因
原因は、/dev/sda と /dev/sdb が入れ替わることがあるためである。
起動時に、OS が認識した順序で /dev/sda、/dev/sdb のようになる。
このため、この順序は入れ替わることがある。
(補足)
・発生頻度が低いため、これまで気付かなかった。
・Linux のパーティション(=LV) については、下記の理由により問題が発生しない。
mdadm + LVM で RAID 1 構成の LVM にしているため、UUID が使用されている。
3. 対処方法
Windows 用のパーティションには、win_1、win_2 のラベルを設定している。
このため、/etc/auto.misc を下記のように変更する。
win_1 -fstype=ntfs,locale=ja_JP.eucJP,umask=022,ro :LABEL=win_1 win_2 -fstype=ntfs,locale=ja_JP.eucJP,umask=022 :LABEL=win_2
(補足)
UUID を使用することも可能である。
(cf. `lsblk -f`)
Gmailのアプリ・パスワードの使用 [misc]
・[安全性の低いアプリの許可] を有効化できなくなったためである。 ・2 段階認証を無効にしている。
また、アプリ・パスワードを使用すると、上記の問題を解決できるとの情報が得られた。
・アプリ・パスワードを使用するには、2 段階認証を有効にする必要がある。 ・アプリ・パスワードの使用により、2 段階認証をバイパスできる。 ・アプリ・パスワードは、Web ブラウザでのログインには使用できない。
よって、アプリ・パスワードを使用するように設定の変更を行った。
手順は、以下の通りである。
1. アプリ・パスワードの生成
(1) SMS の着信の許可
・設定の変更に必要な確認コードを受信するためである。
・確認コードは、050-5840-1910 から送信される。
(2) Web ブラウザでの Gmail へのログイン
(3) 個人情報への電話番号の登録
電話番号の登録を削除しているため、電話番号を再度登録する。
(a) 設定画面の表示
・右上のアイコンから [Google アカウントを管理] を選択
・上部のメニューから [個人情報] を選択
・[連絡先情報] の欄で [電話] を選択
(b) 電話番号の登録
・電話番号を入力
・確認コードを入手
'G-xxxxxx' の 'G-' を除く部分が確認コードである。
・確認コードを入力し、電話番号を登録
(4) 2 段階認証の有効化
(a) 設定画面の表示
・右上のアイコンから [Google アカウントを管理] を選択
・上部のメニューから [セキュリティ] を選択
・[2 段階認証プロセス] を選択
(b) 2 段階認証の有効化
・コードの取得方法として、[テキスト・メッセージ] を選択 (電話番号は、国番号の直後の '0' が削除されて表示される。) ・確認コードを入手 ・確認コードを入力し、変更を実施
(c) バックアップ・コードの入手
・下方の [バックアップ コード] を選択 ・[バックアップ コードを入手しましょう] を選択 ・表示されたバックアップ・コードを保存
(5) アプリ・パスワードの生成
(a) 設定画面の表示
・右上のアイコンから [Google アカウントを管理] を選択
・上部のメニューから [セキュリティ] を選択
・[アプリ パスワード] を選択
(b) アプリ・パスワードの生成
・アプリとデバイスを指定 (例) アプリ=メール、デバイス=その他(パソコン) ・[生成] を選択 ・表示されたアプリ・パスワードを保存 ・[完了] を選択
(6) 後処理
上記で許可した SMS の着信を取り消すことも可能である。
2. アプリ・パスワードの使用
POP/SMTP でのログイン時に、パスワードの代わりにアプリ・パスワードを使用する。
Google検索の不要なポップアップの削除 [misc]
最初は手動で対応していたが、面倒に感じるようになったので、ポップアップ・ウィンドウを消去する対応を行った。
詳細は、以下の通りである。
1. 発生事象
Google 検索において、不要なポップアップ・ウィンドウが表示される。
(1) Google へのログインを促す(確認する)もの
(2) ゴールデンウィークの予定を確認するもの
(補足)
ページの再読み込みを実行すると、ポップアップ・ウィンドウは消える。
2. 対処方法
uBlock Origin に下記の設定を追加する。
!! block popup window on google search ||ogs.google.co.jp/widget/callout … 発生事象 (1) への対応 www.google.co.jp##mobile-promo … 発生事象 (2) への対応
clamav-daemon.serviceの停止処理に想定外の時間を要することへの対応 [Debian]
・clamav-daemon 0.103.3+dfsg-0+deb11u1 (on Debian 11)
1. 発生事象
clamav-daemon.service の停止処理に想定外の時間を要する。
・shutdown 時に、度々発生する。
・90 秒(systemd のタイムアウトのデフォルト値) の待ち時間が発生する。
・clamdscan が実行中か否かに関係なく発生する。
(補足)
・Debian 10 (clamav-daemon 0.103.3+dfsg-0+deb10u1) でも同様の問題が発生する。
・CentOS 7 (clamd-0.103.3-5.el7.x86_64) では発生しない。
2. 対処方法
clamav-daemon.service の停止時のタイムアウト時間を短縮する。
このため、/lib/systemd/system/clamav-daemon.service を編集する。
# diff clamav-daemon.service clamav-daemon.service.org 14d13 < TimeoutStopSec=30
・[Service] 欄の TimeoutStopSec の設定値を変更する。
・停止処理でのタイムアウトまでの時間が変更される。
Windows 10の更新プログラムの構成に失敗することへの対応 [Windows]
・Linux と Windows のマルチブートを行っている。
・Linux の GRUB から Windows 10 (20H2) を起動している。
MBR に インストールした GRUB からチェインロードを行っている。
・普段は、Windows 10 の Windows Update を無効化している。
Windows Update Blocker をいうソフトを使用し、有効/無効を選択している。
・必要時に応じて、Windows Update を有効化し、更新プログラムを適用している。
1. 発生事象
Windows 10 20H2 への KB5005565 の適用で、更新プログラムの構成に失敗する。
[エラー・メッセージ] 更新プログラムの構成に失敗しました
・トラブルシューティング・ツールを実行しても、状況は変わらない。
・クリーン・ブート後に Windows Update を実行しても、状況は変わらない。
2. 対処方法
一時的に、MBR に Windows のブートローダーをインストールすることで改善される。
(1) Windows のブートローダーのインストール
今回は、手近にあった Windows 7 のインストール・ディスクを使用した。
(a) Windows 7 のインストール・ディスクでブートする。
(b) [Windows のインストール] で [次へ] を選択する。
(c) [コンピューターを修復する] を選択する。
(d) [システム回復オプション] 画面で、[次へ] を選択する。
・[Windows の起動に伴う問題の回復用の回復ツールを使用...] の方を選択
・[次へ] を選択
・[コマンド・プロンプト] を選択し、下記のコマンドを実行する。
X:\Sources> diskpart DISKPART> list disk DISKPART> select disk 0 DISKPART> list part DISKPART> select part 1 DISKPART> active DISKPART> exit bootrec /fixmbr exit
(e) ブート用 DVD を取り出し、リブートする。
(2) Windows Update の実行
更新プログラムの構成に失敗しなくなる。
(3) GRUB の再インストール
・GRUB shell 等から Linux を起動する。
・MBR へ GRUB をインストールする。
3. 備考
Windows 10 21H1 への更新についても、同様と思われる。
・更新アシスタントで Windows 10 21H1 への更新を行ったところ、エラーが発生した。
対象とする環境かどうかの判断ができない旨のメッセージが表示された。
・上記の対応後に実施すると、特に問題は発生しなかった。
Windows のブートローダーがイストールされている状態で実施したためと思われる。
また、Windows 7 から Windows 10 (20H2) へのアップグレードでも同様と思われる。
・当初、対象とする環境かどうかの判断ができない旨のメッセージが表示された。
・Windows 10 の評価版のインストールおよび削除後に、再実行すると正常終了した。
cf. https://dan-project.blog.ss-blog.jp/2021-05-29-1
Debian 11のカーネルのバージョンアップ [Debian]
(3.16.0-4-686-pae → 5.10.0-8-686-pae)
1. 実施した理由
カーネルのバージョンが Debian 10.10 と同じことに気付き、確認してみると、カーネルのバージョンアップが行われていなかった。
更新パッケージの適用を定期的に行っているが、何故かカーネルは古いバージョンのままであった。
・Debian 10.10 において、このような状況であった。
・以前は、カーネルのバージョンアップも問題なくできていた。
2. 得られた効果
今回のカーネルのバージョンアップにより、下記の問題が解決できた。
・iptables 1.8.7-1 の起動エラー … (注1)
・apache2 2.4.48 の起動エラー … (注1)
・e2scrub_reap.service (e2fsprogs 1.46.2-2) の起動エラー … (注2)
(注1)
cf. https://dan-project.blog.ss-blog.jp/2021-09-08
(注2)
cf. https://dan-project.blog.ss-blog.jp/2021-09-10
3. 実施手順
今回実施した手順は、以下の通りである。
(1) カーネルのバージョンアップ
[パッケージの更新] # apt-get install linux-image-5.10.0-8-686-pae-unsigned [システムの再起動] # shutdown -r now
(2) apahce のバージョンアップ
# apt-get install libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap # apt-get install apache2 apache2-bin apache2-data apache2-utils
(3) iptables のバージョンアップ
# apt-get install iptables libiptc0 libxtables12
(4) 古いカーネル、不要なパッケージの削除
# dpkg --purge linux-image-3.16.0-4-686-pae # apt-get clean # apt-get autoclean # apt-get autoremove
(5) apparmor の無効化
[サービスの停止] # systemctl stop apparmor # systemctl disable apparmor [システムの再起動] # shutdown -r now [パッケージの削除] … パッケージを削除する場合 # dpkg --purge apparmor
Debian 11への追加対応 [Debian]
これで、アップグレード前の Debian 10.10 と同程度に使用できる状態となったと思われる。
1. 追加対応
1-1. ブート時の e2scrub_reap.service のエラー
(1) 発生事象
(a) エラーメッセージ
Failed to Start Remove Stale Online ext4 Metadata Check Snapshots. see 'systemctl status e2scrub_reap.service' for details.
(b) ブート後の当該サービスの状態
# systemctl status e2scrub_reap.service * e2scrub_reap.service - Remove Stale Online ext4 Metadata Check Snapshots Loaded: loaded (/lib/systemd/system/e2scrub_reap.service; enabled; \ vendor preset: enabled) Active: failed (Result: exit-code) ... Docs: man:e2scrub_all(8) Process: 833 ExecStart=/sbin/e2scrub_all -A -r (code=exited, \ status=218/CAPABILITIES) Main PID: 833 (code=exited, status=218/CAPABILITIES) ... # systemctl is-enabled e2scrub_reap.service enabled
(c) ブート後のサービスの再起動の結果
# systemctl restart e2scrub_reap.service Job for e2scrub_reap.service failed because the control process exited \ with error code. See "systemctl status e2scrub_reap.service" and "journalctl -xe" for \ details.
(2) 対処方法
取り敢えず、当該サービスの自動起動を無効化する。
# systemctl stop e2scrub_reap.service # systemctl disable e2scrub_reap.service
1-2. journald の永続的なジャーナル機能の有効化
(1) 発生事象
journald の永続的なジャーナル機能が有効となる。
(ディスク上の /var/log/journal/ への出力となる。)
(2) 対処方法
無効化するには、下記の手順により、/var/log/journal/ を削除する。
(a) サービスの停止
# systemctl stop systemd-journald.service # systemctl stop systemd-journald.socket
(b) ディレクトリの削除
# rm -fr /var/log/journal
(c) サービスの開始
# systemctl start systemd-journald.socket # systemctl start systemd-journald.service
(補足)
原因は、/var/log/journal/ が存在するためである。
・Debian 11.0 へのアップグレード時に作成されたものと思われる。
・journald の初期設定では、/var/log/journal/ の有無により出力先が変わる。
存在する場合: ディスク(/var/log/jounal/)へ出力
存在しない場合: RAM ディスク(/run/log/journal/)へ出力
1-3. Wireshark の起動エラー
(1) 発生事象
[エラーメッセージ] wireshark: error while loading shared libraries: libQt5Core.so.5: \ cannot open shared object file: No such file or directory
・Wireshark のバージョン: wireshark-qt 3.4.4-1
・該当するライブラリは存在する。
# find /usr/lib -name libQt5Core.so\* /usr/lib/i386-linux-gnu/libQt5Core.so.5.15.2 /usr/lib/i386-linux-gnu/libQt5Core.so.5 … libQt5Core.so.5.15.2 へのリンク /usr/lib/i386-linux-gnu/libQt5Core.so.5.15 … libQt5Core.so.5.15.2 へのリンク
(2) 対処方法
該当するライブラリから、余分な情報を削除する。
# /usr/lib/i386-linux-gnu # cp -p libQt5Core.so.5.15.2 libQt5Core.so.5.15.2.org # strip --remove-section=.note.ABI-tag libQt5Core.so.5.15.2
'for GNU/Linux 3.17.0' という部分が問題の原因とのこと。
(cf. https://myn.meganecco.org/1562249040.html)
# file libQt5Core.so.5.15.2.org libQt5Core.so.5.15.2.org: ELF 32-bit LSB shared object, Intel 80386, \ version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, \ BuildID[sha1]=b682831b8118e8378863be17f9e45a8cd6c66e31, \ for GNU/Linux 3.17.0, stripped # file libQt5Core.so.5.15.2 libQt5Core.so.5.15.2: ELF 32-bit LSB shared object, Intel 80386, \ version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, \ BuildID[sha1]=b682831b8118e8378863be17f9e45a8cd6c66e31, stripped
2. 備考
(1) インストール済のパッケージ数の増減
・Debian 10.10: 1579
・Debian 11.0: 1603 (+24)
(2) ディスクの使用量の増減
・Debian 10.10: 約 3.6GB を使用
・Debian 11.0: 約 3.8GB を使用 (+200MB)