こんにちは、SSTでWeb脆弱性診断用のツール(スキャンツール)開発をしている坂本(Twitter, GitHub)です。
先日の記事では Linux のネットワークインターフェイス名を出発点として systemd や udev について調査しました。 どうやって調査したかというと、
- 検索キーワードをあれこれ試してみて、見つかった記事から気になるコマンドや設定ファイルがあれば、実際の内容を確認し、
- そこからmanページを辿ってパッケージ情報にさかのぼり、パッケージがインストールした他のコマンドや設定ファイルの一覧から構成を把握し、
- さらに関連するコマンドや設定ファイルをmanページで辿って・・・
というサイクルを繰り返しました。 時には同じmanページを数度に渡って辿り直し、読み直したりして自分の中の情報を整理しました。
読者の皆様は、そのような時どうされますか?
初めて触るLinuxディストリビューション、初めて触れるコマンド、設定ファイル・・・。
そこからどうやって「こういう構成を実現したい」「このエラーを解決したい」まで辿り着きますか?
あるいは、書籍やWeb記事で見様見真似でコマンドを実行したり設定ファイルを編集したけど、うまく動かない・・・。
そんな時に、何をヒントに調査を開始しますか?
本記事では「ログの確認」と「パッケージ情報の調査」という観点から、上記のような状況で筆者がよく使う(= ヒントとする)コマンドを紹介していきます。
- 「ログの確認」は今まさに起こっている現象を調べるのに役立ちます。
- 「パッケージ情報の調査」はコマンドや設定ファイル単体からひとつ上のレベル、パッケージのレベルでソフトウェアの構成や仕組みを理解するのに役立ちます。
筆者の場合、「ログという動的な情報」と「パッケージ情報という静的な構造」を重ね合わせることでシステムの理解を深めていきます。 それにより「このシステムではこういう構成になっているから、この設定ファイルをこのように修正する必要がある」と、目の前のシステムにとって一番適切で安定と思われる方法を探すように意識しています。 多少遠回りになるときもありますが、長期的には安定して運用できるアプローチだと考えています。
本記事では上記2点の調査方法の紹介に加え、以下についても紹介します。
- manページのセクション番号や探し方
- 実際の調査や思考過程、ネットで検索するときのキーワード選定
本記事は Linux 初心者や入門レベルの方に特にオススメです。 単に書籍や記事のコマンドや設定ファイルを丸写しするだけでなく、そこから一歩進んで知識を深めたい時に活用できると思います。
本記事が対象とする Linux ディストリビューション:
- Red Hat Linux 系 : Red Hat Enterprise Linux, CentOS, Amazon Linux など、
.rpm
によるパッケージ管理をしているディストリビューション - Debian 系 : Debian, Ubuntu など
.deb
によるパッケージ管理をしているディストリビューション - いずれも systemd 導入以降のバージョンを対象とします。
上記以外のディストリビューションでも、パッケージ管理について本記事で紹介しているのと同等のコマンドを把握すれば、同様の調査が可能となります。
本記事で紹介したコマンドの動作確認環境:
[1] CentOS 8 Stream $ cat /etc/os-release NAME="CentOS Stream" VERSION="8" ID="centos" ID_LIKE="rhel fedora" VERSION_ID="8" PLATFORM_ID="platform:el8" PRETTY_NAME="CentOS Stream 8" ANSI_COLOR="0;31" CPE_NAME="cpe:/o:centos:centos:8" HOME_URL="https://centos.org/" BUG_REPORT_URL="https://bugzilla.redhat.com/" REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux 8" REDHAT_SUPPORT_PRODUCT_VERSION="CentOS Stream" ------------------------------------------- [2] Ubuntu Server 20.04 LTS $ cat /etc/os-release NAME="Ubuntu" VERSION="20.04.2 LTS (Focal Fossa)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 20.04.2 LTS" VERSION_ID="20.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=focal UBUNTU_CODENAME=focal
man ページについて
ファイルやコマンドの紹介に入る前に、manページについて解説します。 manページはコマンドや設定ファイルの解説が書かれている一次情報になります。 Linuxの勉強をするときも、一つ一つのコマンドについてmanページを確認して、使い方を勉強していきます。
まぁ、大体英語だったりするし、対象のオプション解説で圧倒されて全部読むことは筆者も含め無いと思いますが・・・。
それでも、拾い読みだけでも結構ヒントを掴めたりするので、やはりmanページは重要です。 またお仕事等で人に説明するときも、「ネットで検索した記事に書いてありました」より「manページで確認しました」の方が信頼性が高いと思われます。 マイナーなコマンドではそもそもネットで検索しても日本語の解説記事が無かったりもするので、最後の砦としてmanページは外せません。
重要なのは、manページのセクション番号と探し方です。
man ページのセクション番号
Linuxコマンドの解説記事などで "ps(1)" や "ip(8)" など「コマンド名」 + 「( 数字 )」で表記されているのを目にした方もいると思いますが、「(数字)」部分がセクション番号です。
これは man コマンドに対して man 1 xxx
などコマンドライン引数として指定することができます。
manページの種類に応じて 1 ~ 9 までのセクション番号があります。 *1
1 Executable programs or shell commands 2 System calls (functions provided by the kernel) 3 Library calls (functions within program libraries) 4 Special files (usually found in /dev) 5 File formats and conventions eg /etc/passwd 6 Games 7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) 8 System administration commands (usually only for root) 9 Kernel routines [Non standard]
例えば sysfs
というmanページを例に取ると、セクション2 と セクション5 の二種類があります。
man 2 sysfs
(sysfs(2)
) : プログラミングで使うsysfs()
関数の使い方についてのmanページです。man 5 sysfs
(sysfs(5)
) : sysfs そのもののファイルシステムの構造や仕組みについてのmanページです。
このように同じトピックスについて複数のセクションが用意されていることがあります。 自分が調べたいmanページがどれなのか、注意が必要です。
Linux システムを勉強したい用途であれば、大抵はセクション 1, 5, 7, 8 あたりが対象になります。
もし間違ったセクションを参照しても、特にセクション 2, 3 あたりであれば #include ...
のようなC言語でのinclude文の解説などがあるので、それで見分けることができます。
しかし、そもそも調べたいトピックがmanページにあるか、どうやって調べれば良いでしょうか? 仮にあったとして、セクション番号がどれか調べるにはどうすれば良いでしょうか?
そのためには man ページの探し方を知っておく必要があります。
man ページの探し方
man ページを探すには、目の前のLinuxシステムの中で探す方法と、Webから探す方法があります。
- 目の前のLinuxシステムの中で探す方法
man -k (キーワード)
で探します。- 例1:
man -k /etc/fstab
→/etc/fstab
のフォーマットについて書かれたmanページが見つかります。 - 例2:
man -k sysfs
→sysfs(2)
とsysfs(5)
が表示されれば、sysfs(5)
の方がファイルシステムについてのmanページであることが分かります。
- 例1:
find /usr/share/man
でmanページが格納されたファイル一覧を取得し、ファイル名でgrepする方法もあります。
- Webから探す方法
- 使用している Linux ディストリビューションのドキュメントサイトを探し、検索する。
- Debian Buster の例: https://manpages.debian.org/contents-buster.html
- JM Project (Linux 関連マニュアルの日本語ページ) から探す。
- 使用している Linux ディストリビューションのドキュメントサイトを探し、検索する。
Webから探す方が、たくさんタブを開いて複数を並べて表示できるので便利です。 一方で、目の前のLinuxシステムの中から探す方が、実際にインストールされているバージョンのmanページを表示できます。 Webから探した場合、実際にインストールされているバージョンと異なるバージョンのmanページが見つかる場合があるので、その点に注意が必要です。
以降、本記事で Linux コマンドを紹介する際は コマンド名(manページセクション名)
のように表記するに留め、manページへのURLリンクは省略します。
それぞれの方法で随時参照してください。
ログの確認
今まさにシステムで起こっている現象や、システムの状態を確認します。
- Linuxコマンドの細かい使い方についてはそれぞれのmanページやネット検索を参照してください。
- コマンドによってはお使いのディストリビューションでデフォルトでインストールされていない場合もあるので注意してください。
- いわゆる「ログファイル」の他に、システムの状態を確認するコマンドも載せています。
- 目の前にシステムで何が起こっていたのか、起こっているのかを確認するための入り口全体を紹介しています。
- 紹介しているコマンドの中には root ユーザまたは
sudo
でしか動かなかったり、一般ユーザと root (orsudo
) とで結果が異なるものもあります。- システム管理者しかアクセスできないディレクトリやファイルを参照することも多いので、rootユーザ または
sudo
で実行することを筆者は推奨します。
- システム管理者しかアクセスできないディレクトリやファイルを参照することも多いので、rootユーザ または
以下、ログやコマンドの詳細です。
- 一般的なシステムログ
dmesg
- kernelが出力したメッセージを表示する。長いので、
dmesg | less
やdmesg | grep xxx
などにパイプでつなげることが多い。
- kernelが出力したメッセージを表示する。長いので、
/var/log/messages
- kernelなどのシステムログ。特定のログファイルに分類されないログがこちらに出てくることもある。
/var/log/maillog
- メール関連のログ。メールシステムを扱う時はこちらのログを参照する。
- その他、
/var/log/
以下のログファイル全般- OSによってログファイルの名前や分類が異なるので、対象とするシステムの
/var/log/
以下を都度参照のこと。 - 最近の Linux だと
/etc/rsyslog.conf
でシステムログのカテゴリ毎にどのログファイルに出力するかの設定があるので、それも参照のこと。- このあたりの設定は
man -k syslog
で出てくる syslog 系のmanページを手当たりしだいに読み漁ると、どこかで見つかる。
- このあたりの設定は
- OSによってログファイルの名前や分類が異なるので、対象とするシステムの
- 特定サービスのログ
sudo systemctl {enable|disable|start|stop|restart|status} サービス名
で管理するサービスが対象。sudo journalctl -u サービス名
でログを確認できる。- システムに登録されているサービスの一覧を取得
sudo systemctl list-unit-files
- サービスの今の状況を確認したい
sudo systemctl status サービス名
- サービスを起動|停止|再起動したい
sudo systemctl {start|stop|restart} サービス名
- システム起動時にサービスの自動起動をON/OFFしたい
sudo systemctl {enable|disable} サービス名
- システムとkernelのバージョン
uname -a
: Linux kernel のバージョン情報/etc/os-release
: Linux ディストリビューションのバージョン情報- その他,
ls /etc/*release
やls /etc/*version
などでリリースやバージョン情報が書かれたテキストファイルを調査できる。 - 強制アクセス制御(MAC: Mandatory Access Cotnrols) の状態
- SELinux :
sudo getenforce
(Red Hat Enterprise Linux/Fedora/CentOS系) - AppArmor:
sudo aa-status
(Ubuntu, openSUSE系)
- SELinux :
- プロセス情報
ps(1)
: プロセス一覧, CPU/メモリ使用量, コマンドライン文字列などps auxww
,ps -ef
など
pstree(1)
: プロセスの親子関係をツリー状に表示lsof(8)
: プロセスごとにオープンしているファイル一覧の表示/proc
,proc(5)
: プロセス情報をファイルシステムとして参照できる。
- ネットワーク設定
ip(8)
: ネットワークデバイス設定の操作と表示ip a
: インターフェイスごとのアドレス設定表示ip r
: ルーティングテーブル表示
ss(8)
: socket接続状況の表示ss -tanp
: listening socketごとのプロセス情報表示
- CPU/メモリ/IO使用状況
top(1)
: CPU使用率/メモリ消費量などリソース使用状況のリアルタイム表示free(1)
: メモリ使用率の表示free -h
など
df(1)
: ディスク使用率の表示df -h
など
du(1)
: ファイル/ディレクトリ単位でのディスク使用量の表示du -h
など
iostat(1)
: CPUとI/O使用状況の時系列レポートvmstat(8)
: CPUとメモリ使用状況のレポート
- デバイス情報
lscpu(1)
: CPU情報の表示lsblk(8)
: ストレージなどのブロックデバイスの表示lsusb(8)
: USBデバイスの表示lspci(8)
: PCIバス接続デバイスの表示/sys
,sysfs(5)
: kernel object をファイルシステムとして参照できる。- https://manpages.debian.org/buster/manpages/sysfs.5.en.html
- デバイスの検出状況などを確認できる。
udev(7)
: デバイス管理udevadm(8)
: udev管理ツール- 例1,
udevadm info /sys/class/net/eth0
: eth0 のデバイス情報を表示 - 例2,
udevadm test /sys/class/net/wlan0
: wlan0 を認識したときのudev処理(ルール適用状況など)のデバッグ表示 - 参考:
第559回 デバイスの認識をモニタリング・コントロールできる「udevadm」:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社
- 例1,
- system call のトレース
strace(1)
- ファイル操作関連の system call トレース:
strace -o trace-log --trace=file command arg1 arg2 ...
- ネットワーク関連の system call トレース:
strace -o trace-log --trace=network command arg1 arg2 ...
- ファイルとネットワーク両方:
strace -o trace-log --trace=file,network command arg1 arg2 ...
- ファイル操作関連の system call トレース:
ps(1)
やCPU/メモリ使用量については非常に奥が深く、筆者も完全に理解できてはいません。
ps(1)
はコマンドオプションが複雑ですし、free(1)
等のメモリ使用状況についても表示されるカラムの意味について正しく把握することが重要です。
適宜ネットを検索してみて、実際にどのようにオプションを組み合わせるのかや、表示内容の意味について確認してみてください。
パッケージ情報の調査
コマンドや設定ファイルをヒントにパッケージ情報にさかのぼり、そこからソフトウェア構成全体を俯瞰するのがパッケージ情報の調査の醍醐味です。
Linuxディストリビューションでは実行ファイル/設定ファイル/manページなどを「パッケージ」というアーカイブファイルにまとめます。 パッケージは一覧としてデータベース化され、インターネットからダウンロードできるよう「パッケージリポジトリ」に配置されます。 Linuxをインストールすると、パッケージリポジトリを参照してインストールや更新を行う「パッケージマネージャ(管理ツール)」が組み込まれます。 ユーザはパッケージマネージャを使って必要なパッケージをインストールしたり、システムをアップデートします。
パッケージとその管理ツールはLinuxディストリビューション毎に異なりますが、本記事では大きく以下の2種類を扱います。
- Red Hat Enterprise Linux/Fedora/CentOS系
- パッケージファイルの拡張子は
.rpm
- 管理ツールとしては
rpm(8)
やyum(8)
, 最近はdnf(8)
があります。 rpm(8)
は主にローカルで.rpm
パッケージの管理や開発で使います。yum(8)
やdnf(8)
はインターネット上の「パッケージリポジトリ」を参照し、インターネットからパッケージをインストールしたり最新パッケージをダウンロードして更新するのに使います。
- パッケージファイルの拡張子は
- Debian/Ubuntu系
- パッケージファイルの拡張子は
.deb
- 管理ツールとしては
dpkg(1)
やapt(8)
があります。 dpkg(1)
は主にローカルで.deb
パッケージの管理や開発で使います。apt(8)
はインターネット上の「パッケージリポジトリ」を参照し、インターネットからパッケージをインストールしたり最新パッケージをダウンロードして更新するのに使います。
- パッケージファイルの拡張子は
特定コマンドや設定ファイルをヒントに知識を深めたい場合、筆者は次のような流れでアプローチします。
- コマンドや設定ファイルのファイルシステム上のフルパスを調査し、それを含むパッケージを探す。
- パッケージが既知であれば、システムにインストールされたパッケージ一覧から探すこともある。
- インストールされていない場合は、パッケージリポジトリ上から検索する。
- パッケージ情報が見つかったら、その概要を確認する。
- インストール済みであれば、パッケージに含まれるファイル一覧を取得する。
- ここから関連する他のコマンド, 設定ファイル, manページの情報を辿ります。
- 発展型として、依存パッケージやchangelogを確認することもあります。
コマンド/設定ファイル → インストール元パッケージ → インストールされたファイル一覧の順で辿ることで、そのソフトウェアの全体像が見えてきます。
上記の流れで、.rpm
/ .deb
系それぞれのコマンドを紹介します。
- 詳細なコマンドラインオプションはmanページや、以下に続く「0. 参考資料」を参照してください。
- 新しい rpm 系では
yum
をdnf
に読み替えてください。
コマンドラインオプションによってはバージョンが古い or 新しいと使えない可能性もあります。 実際のLinuxシステム上でのmanページも必ず確認するようにしてください。
0. 参考資料
公式サイトのドキュメントおよびmanページを紹介します。 ネット上にもたくさん解説記事がありますので、そちらもあわせて検索してみてください。
- rpm.org - Documentation
- https://rpm.org/documentation.html
- rpm パッケージ/コマンド開発元の公式ドキュメント。主にrpmパッケージを作る人向け。
- yum
- http://yum.baseurl.org/
- yum開発元のサイト。2021年現在は dnf の方が推奨されている。
- dnf
- https://github.com/rpm-software-management/dnf
- rpm系の最新のパッケージマネージャ。yumの代替として、最新の Red Hat Enterprise Linux や CentOS で標準のコマンドとして採用されている。
- ドキュメントサイトは readthedocs.io でホストされている。
- Debian 管理者ハンドブック - 5.4. dpkg を用いたパッケージの操作
- Debian Buster (10) ベースのmanページ
- dpkg(1)
- dpkg-query(1)
- apt(8)
- https://manpages.debian.org/buster/apt/apt.8.en.html
apt-get(8)
やapt-cache(8)
のフロントエンドとしても動作するため、一部オプションはそちらのmanページに記載されていることがあります。
- apt-cache(8)
- apt-get(8)
- Linux基本コマンドTips - @IT
- https://atmarkit.itmedia.co.jp/ait/series/3065/
- rpm, yum, dnf, dpkg, apt などの解説が豊富です。連載記事の一覧からタイトルで探してください。
- YUMコマンドチートシート for Red Hat Enterprise Linux
- 有志によるコマンドオプションまとめ記事
1. ファイルパスからインストール元パッケージを探す
rpm -qf
か dpkg -S
を使います。
実行ファイル /bin/ps
から探す例:
[rpm系] $ sudo rpm -qf /bin/ps procps-ng-3.3.15-6.el8.x86_64 [deb系] $ sudo dpkg -S /bin/ps procps: /bin/ps
設定ファイル /etc/os-release
から探す例:
[rpm系] $ sudo rpm -qf /etc/os-release centos-stream-release-8.5-3.el8.noarch [deb系] $ sudo dpkg -S /etc/os-release base-files: /etc/os-release
注意点: symbolic link や hard link されたファイルパスでは見つからないこともあります。
例として /bin/ps
と /usr/bin/ps
が同じファイルを指すよう hard link されているとします。
$ ls -li /bin/ps /usr/bin/ps 2756518 -rwxr-xr-x 1 root root 83584 May 31 2018 /bin/ps 2756518 -rwxr-xr-x 1 root root 83584 May 31 2018 /usr/bin/ps (→ 同じ i-node なのでhardlinkされていると思われる)
この場合、 /bin/ps
ではパッケージが見つかりますが、 /usr/bin/ps
では見つかりませんでした。
$ sudo dpkg -S /bin/ps procps: /bin/ps $ sudo dpkg -S /usr/bin/ps dpkg-query: no path found matching pattern /usr/bin/ps
上記は hard link というやや珍しいケースですが、設定ファイルなどは symbolic link の場合もあります。 rpm/dpkg コマンドで探す前に、symlinkかそうでないか確認し、symlinkの場合は実体ファイルの方で探すのを推奨します。
もう一つ特殊なケースとして、パッケージのインストールや更新時のhookスクリプトにより生成されたファイル、というケースがあります。 rpmもdebも、インストールや更新時にカスタムスクリプトを動かすことができます。 サーバ用のパッケージを例にすると、そのサーバ専用のユーザを useradd コマンドで追加するなどがあります。 そのようなカスタムスクリプトにより生成されたファイルは、パッケージ中のファイル一覧には情報として含まれないため、上記のコマンドで探しても対応するパッケージが見つかりません。
この場合は、まずはパッケージ名を特定します。 参考資料などからパッケージ名を特定できれば、パッケージに含まれるカスタムスクリプトを抽出して、その中で生成されたものであるかどうか確認することができます(後述)。
システムにインストール済みのパッケージ一覧から探す
ソフトウェアのパッケージ名、あるいは製品名が分かっていれば、システムにインストール済みのパッケージ一覧から検索することができます。
インストール済みのパッケージ一覧を取得する例:
[rpm系] $ sudo rpm -qa [deb系] $ sudo dpkg -l
実際は sudo rpm -qa | less
や sudo dpkg -l | grep xxx
等にパイプで流し込み、パッケージ名や製品名で絞り込むことになります。
パッケージリポジトリ全体から探す
対象のパッケージがまだインストールされていない場合、 rpm -qa
や dpkg -l
には表示されません。
そのような時はパッケージリポジトリ全体から探すことができます。
パッケージリポジトリにはインストールしていないパッケージも含め、一覧で管理されているため、そのような検索が可能です。
パッケージリポジトリ全体から探す場合は事前にパッケージ名あるいはその一部を確認しておき、キーワードとして探すことになります。
例: "postgresql" で始まるパッケージ一覧の検索
[rpm系] $ sudo yum list postgresql* Loaded plugins: extras_suggestions, langpacks, priorities, update-motd Installed Packages (... インストール済みのパッケージ一覧 ...) Available Packages (... インストールしていんけどリポジトリににはあるパッケージ一覧 ...) [deb系] $ sudo apt list postgresql*
なお deb系については sudo apt search postgresql*
とすると、パッケージ情報の中も含め全文検索した結果を表示してくれます。
ちなみに rpm -qf
や dpkg -S
のように、ファイルパスでパッケージリポジトリ全体を検索できるでしょうか?
調べた範囲では rpm
系ではそのような方法が見つかりませんでした。
一方で deb
系では apt-file
パッケージが提供する apt-file(1)
コマンドを使うとそのような検索ができそうです。
- apt-file(1)
- 【 dpkg 】コマンド/【 apt-file 】コマンド/【 apt-show-versions 】コマンド――コマンドのインストール元パッケージとバージョンを確認する:Linux基本コマンドTips(246) - @IT
apt
パッケージとは別になっているため、利用するには別途 apt install apt-file
でパッケージをインストールする必要があるかもしれません。
本記事では検証していませんが、使ってみたい方は上記manページや記事を参照してみてください。
2. パッケージ情報の表示
パッケージ名が特定できたら、バージョン情報等を確認します。
- rpm 系の場合、インストール済みのパッケージについては
rpm -qi
で、未インストールを含むパッケージリポジトリ全体についてはyum info
で確認します。 - deb系の場合、
apt show
で確認します。dpkg -p
も使えますが、apt フロントエンドを使う場合はapt-cache show
(=apt show
) を使うようにとdpkg(1)
のmanページに記載がありました。- 今回動作確認した環境では、
dpkg -l
では確かにopenssh-server
がインストールされているのにdpkg -p openssh-server
ではdpkg-query: package 'openssh-server' is not available
となるケースが確認されたため、apt show
の方を優先して紹介します。
詳細なバージョン情報や開発元のWebサイト情報が含まれており、重要なヒントとなります。
例1: インストール済みの "procps-ng"/"procps" パッケージ情報の表示
[rpm系] $ sudo rpm -qi procps-ng [deb系] $ sudo apt show procps
例2: まだインストールしていない postgresql パッケージ情報をパッケージリポジトリから取得
[rpm系] $ sudo yum info postgresql [deb系] $ sudo apt show postgresql
3. パッケージに含まれるファイル一覧の取得
ここまで来れば、あとはパッケージに含まれる = パッケージがインストールするファイル一覧を表示します。
インストール済みパッケージの場合、rpm系なら rpm -ql
, deb系なら dpkg -L
コマンドで表示できます。
[rpm系] $ sudo rpm -ql procps-ng /usr/bin/free (...) /usr/bin/ps (...) /usr/share/doc/procps-ng-3.3.10 (...) /usr/share/man/man1/ps.1.gz [deb系] $ sudo dpkg -L procps (...) /bin/ps (...) /usr/share/doc/procps (...) /usr/share/man/man1/ps.1.gz (...)
→ 実行ファイルの他に、ドキュメントや man ページ用のファイルが含まれていることが分かります。
ファイル一覧から、関連するコマンドや設定ファイル、manページが分かるので非常に重要なヒントとなります。
なおインストールしていないパッケージについては、筆者が調べた範囲ではyum/aptともにファイル一覧まで取得するコマンドが見当たりませんでした。 執筆時点では本記事の対象外とさせてください。 ご存じの方いたら教えてください。
deb系については /var/lib/dpkg/info/
の下に インストールしたパッケージ名.list
というファイルも作成されます。
こちらもパッケージに含まれるファイル一覧の内容になっています。
またrpm系については以下のコマンドラインオプションを使うと、その所有者情報も含めてファイル一覧を表示します。
$ sudo rpm -q --qf "[%{FILEMODES:perms} %{FILEUSERNAME}:%{FILEGROUPNAME} %{FILENAMES}\n]" <package-name>
ほとんどの調査ではここまでの探索で必要な情報が分かります。 しかし調査目的によってはさらに踏み込んだ探索が必要な場合があります。 例として以下のようなケースがあります。
- 「このパッケージをインストールしたときに、依存してインストールされたパッケージを知りたい」
- 「脆弱性対応やバグ修正状況を確認したいので、changelogも見たい」
- 「明らかにこのパッケージが使用しているのに、ファイル一覧に出てこない。インストール/更新時のカスタムスクリプトを確認して、そこで生成しているか調べたい」
以下、発展型としてそれぞれのケースについて、対応するコマンドを紹介していきます。
なおここまで来ると、対象のパッケージはシステムにインストール済みのものがほとんどです。 システムにインストールしていないケースについては対象外とさせていただきます。
依存パッケージの表示
foo
パッケージをインストールしようとすると、foo-lib
や libxxx
, libyyy
なども一緒にインストールされることがあります。
これは foo
は foo-lib
, libxxx
, libyyy
に依存しているという情報が foo
のパッケージ情報に書き込まれており、それを読み取ったパッケージ管理ツールが依存するパッケージを一緒にインストールしてくれるためです。
こうしたパッケージの依存関係も、ソフトウェア構成を理解するときのヒントになります。
- rpm系の場合、ローカルにインストール済みのパッケージについては
rpm -qR
orrpm -q --requires
で表示できます。- まだインストールしていないパッケージについては
yum deplist
でパッケージリポジトリから参照することができます。
- まだインストールしていないパッケージについては
- deb系の場合、
apt depends
でパッケージリポジトリ全体から参照できます。- 調べた範囲では
dpkg
コマンド単体で依存関係のみを表示する機能は無いようです。dpkg -p
で表示される内容に依存関係も含まれているので、そこで参照する他無いようです。
- 調べた範囲では
[rpm系] (インストール済みの openssh-server が依存するパッケージを表示) $ rpm -qR openssh-server (インストールしていない postgresql が依存するパッケージを表示) $ sudo yum deplist postgresql [deb系] (インストール済みの openssh-server が依存するパッケージを表示) $ sudo apt depends openssh-server (インストールしていない postgresql が依存するパッケージを表示) $ sudo apt depends postgresql
参考:
- software installation - How can I check dependency list for a deb package - Ask Ubuntu
- command line - How to list dependent packages (reverse dependencies)? - Ask Ubuntu
- How to Check Dependencies of a Package in Ubuntu Linux
changelogの表示
バグ修正やセキュリティアップデートの状況を詳細に確認したい場合、changelog(修正履歴)も調査することがあります。 Linuxディストリビューションによりメンテナンスされているパッケージの場合、changelogが記載されたファイルがドキュメントとしてインストールされることが多いです。 また、パッケージ情報にchangelogが埋め込まれていて、パッケージ管理ツールを使って表示できる場合もあります。
- rpm系の場合、ローカルにインストール済みのパッケージについては
rpm -q --changelog
で表示できます。 - deb系の場合、ローカル/パッケージリポジトリ含めて
apt-get changelog
で表示できます。
[rpm系] (インストール済みの openssh-server のchangelogを表示) $ sudo rpm -q --changelog openssh-server [deb系] (インストール済みの openssh-server のchangelogを表示) $ sudo apt-get changelog openssh-server (インストールしていない postgresql のchangelogを表示) $ sudo apt-get changelog postgresql
パッケージがインストールしたchangelogを探す場合は、 rpm -ql
や dpkg -L
でパッケージがインストールしたファイル一覧から探します。
パッケージによっては changelog ファイルが含まれていない場合もあるため注意してください。
[rpm系] $ sudo rpm -ql openssh | grep -i changelog /usr/share/doc/openssh/ChangeLog [deb系] $ sudo dpkg -L openssh-client | grep -i changelog /usr/share/doc/openssh-client/changelog.Debian.gz
参考:
- RPMパッケージのCHANGELOGを確認する - Qiita
- debian - Use dpkg to view changelog - Unix & Linux Stack Exchange
- How do I see the changelog for a debian/ubuntu deb package? - Server Fault
カスタムスクリプトの表示
「このファイル、明らかにあのパッケージがインストールしたはずなのに rpm -ql
や dpkg -L
で表示されない・・・」
そんな時は、パッケージに埋め込まれたカスタムスクリプトを確認してみてください。
- rpm系の場合
- "scriptlet" という仕組みでパッケージのインストールやアンインストール時に実行するスクリプトを埋め込むことができます。
rpm -q --scripts
で表示します。 - "trigger" という仕組みで、他のパッケージが何かする時に、トリガーとしてスクリプトを動かすこともできます。
rpm -q --triggers
で表示します。
- "scriptlet" という仕組みでパッケージのインストールやアンインストール時に実行するスクリプトを埋め込むことができます。
- deb系の場合
- "preinst", "postinst", "prerm", "postrm" スクリプトという仕組みでインストール or 削除の前後で実行するスクリプトを埋め込むことができます。
- "triggers" という仕組みで他のパッケージと連携する仕組みもあるようです。こちらは詳しくは理解しきれていないのですが、rpm系の"trigger" と同等の仕組みと推測します。
- いずれもパッケージ内の制御ファイルという位置づけのようで、
/var/lib/dpkg/info/
ディレクトリ以下にインストールしたパッケージ名.{preinst|postinst|prerm|postrm|triggers}
というファイル名で展開されます。
[rpm系] $ sudo rpm -q --scripts systemd $ sudo rpm -q --triggers httpd $ sudo rpm -q --triggers --scripts httpd [deb系] (systemd パッケージの制御ファイル一覧を表示) $ ls /var/lib/dpkg/info/systemd.* | cat systemd.conffiles systemd.list systemd.md5sums systemd.postinst systemd.postrm systemd.preinst systemd.prerm systemd.triggers
参考:
- rpm系
- deb系
4. サマリ
ここまでのパッケージ調査系コマンドについて、以下にサマリ(チートシート)としてまとめます。
やりたい事 | rpm系 | deb系 |
---|---|---|
ファイルパスからインストール元パッケージを探す | rpm -qf file-path |
dpkg -S file-path |
インストールしたパッケージの一覧 | rpm -qa |
dpkg -l |
パッケージリポジトリからパッケージ名を検索 | yum list (package-name)* |
apt list (package-name)* apt search text-search-keyword |
パッケージ情報の表示 | rpm -qi (package-name) yum info (package-name) |
apt show (package-name) |
パッケージが含むファイル一覧 | rpm -ql (package-name) |
dpkg -L (package-name) |
依存パッケージの表示 | rpm -qR (package-name) yum deplist (package-name) |
apt depends (package-name) |
changelog表示 | rpm -q --changelog (package-name) rpm -ql (package-name) | grep -i changelog |
apt-get changelog (package-name) dpkg -L (package-name) | grep -i changelog |
カスタムスクリプト表示 | rpm -q --scripts (package-name) rpm -q --triggers (package-name) |
ls /var/lib/dpkg/info/(package-name).* → .(pre|post)(inst|rm) や .triggers ファイルを確認 |
注意:
sudo
は省略しています。- 新しい rpm 系では
yum
をdnf
に読み替えてください。
調査の心得:「目の前のもの全てがヒント」
「ログの確認」と「パッケージ情報の調査」について紹介しました。
実際にこれらをどう組み合わせて調査していけば良いでしょうか?
ネット検索も含めた、筆者なりの調査方法を紹介していきます。
調査の心得は 「目の前のもの全てがヒント」 です。
ポート番号からプロセス名→実行ファイルフルパス、設定ファイルをヒントに調べる
よくあるのが「TCP:8080番で動いてるサービスは何?」という調査です。
目の前でTCP:8080番で動いているサービスがあるのなら、システムにログインして TCP:8080 番というヒントだけで芋づる式に辿ります。
sudo ss -tanp
でTCPを listen しているプロセスIDとプログラム名一覧を取得 → 8080 番を listen しているのをメモ。- プログラム名が分かるのでこの時点で
man プログラム名
あるいはman -k プログラム名
、もし複数セクションがあるならman セクション1, 5, 7, 8 あたりをチェック。 ps auxww
からプロセスIDが合致するものを探し、実行ファイルのフルパスや実行時のコマンドライン引数を確認。- 実行ファイルのフルパスがわかれば
rpm -qf
ordpkg -S
でパッケージを検索、あとはパッケージ情報やファイル一覧から他のコマンド/設定ファイル/manページを芋づる式に辿る。- パッケージ情報とファイル一覧:
rpm -qil
,dpkg -L
,apt show
- 設定ファイルがあれば
man 5 設定ファイル名
- パッケージ情報とファイル一覧:
- 設定ファイルが入っているディレクトリがあれば、同じディレクトリに
.bak
や.orig
等のバックアップファイルが無いかチェック。- あれば
diff
コマンドで差分を確認する。小さな差分があれば、変更された設定項目について man ページを確認。 - ディレクトリ名から、ソフトウェアの名前やパッケージ名らしき箇所を取り出して
man -k
する、あるいはネットで検索する。
- あれば
ここまで、全てローカルシステム上のパッケージ管理やシステムユーティリティだけで調査できます。
ポイントは ps
コマンドでプロセスを特定するところです。
動いているプロセスとそのプロセスIDを特定できれば、コマンドライン引数などから「コマンド名」「実行ファイルのフルパス」「設定ファイル」「設定ディレクトリ」などのヒントが分かります。
あとはパッケージ管理ツールと man コマンドでひたすら辿り、情報を収集・整理していくだけです。
なおLinuxシステムを調査する場合、システム管理者しかアクセスできないディレクトリやファイルを調べることが多いので、システム管理用の sudo
可能なユーザ、または root ユーザで調査するのを筆者としては推奨します。
単語をヒントに検索キーワードをひねり出す
「こういう設定をしたいけど、どこから始めれば分からない」時はネット検索のお世話になります。
しかし検索キーワードを工夫しないと、ネットの叡智も応えてくれません。
筆者の場合、とりあえず「Linuxディストリビューション名」と、 設定したい内容を無理やり英単語にしたもの のを検索窓に投げます。 ポイントは英語で検索することです。 英語で検索することで、近い記事も遠い記事も全て出てきます。 「それじゃ答えにたどり着けないじゃないか?」とお思いですが、 欲しいのは答えそのものではなく、答えに近づくための検索キーワードです。 思い出してください、「目の前のもの全てがヒント」です。 最初から正解だけを求める必要はありません、いくら的はずれな検索キーワードを出発点にしても、 検索結果そのものからより精度の高いキーワードを拾い上げていけば、最終的に正解にたどり着けます。
なので、とりあえず上位2-3件程度はタブで開いてみてざっと流し読みします。 その上で「あ、こういう設定って、 英語だとこういう表現もするのか 」とか、「やってることは違ってそうだけど、 こんなコマンドもあるんだ」とか、 「もっと詳しく書かれてそうなスレッドへのリンクが貼ってあるから見てみよう」など、ヒントになりそうな要素を片っ端から探します。 拾い上げたキーワードを使って、さらに検索を続けます。 そうしていくと、徐々に本当に自分が検索したいキーワードが見えてきます。 その頃には、検索結果に正解そのものか、正解に近い記事がちらほらと出てきます。
難しいのは「最初のキーワード」でしょう。 できれば英語で「how to ~」としたいところですが、うまく思いつかないようであれば単語レベルでも構いません。 Linuxシステム関連の検索であれば、Stack Exchange や Stack Overflow のサイトのスレッドが結果に出てくることも多いです。 そうしたスレッドは、そもそも英文で質問が書かれてます。 それを参考にすれば良いだけです。 検索結果そのものはハズレでも、その中に次の検索キーワードが埋まっていないか探せば良い のです。
公式ドキュメントと解説記事を行ったり来たりする
man ページを読んだりネット検索を繰り返していると、そのうち「そろそろ公式ドキュメントを読んだほうが良いかな・・・」となってきます。
そこで公式ドキュメントを探して "Document" リンクなどを辿るわけですが、最初に読む時は何がなんだかさっぱり分からないこともあります。
それでも大丈夫です。
公式ドキュメントを読んでも分からないときは、素直にネット検索で「もっと分かりやすく解説している記事」を探します。
このフェーズでは「自分にとってわかりやすいかどうか」が最優先で、情報の正確性は後回しです。
自分の中でソフトウェアの構成や仕組みのイメージを構築するのが先で、情報の正確性はその後です。 (あくまでも筆者の場合です。)
真面目に言い換えるなら、 「公式ドキュメントに出てくる単語とか言い回しを、他の記事で予習しておく」 のがポイントです。
十分予習して、「公式ドキュメントに何が書いてあるのか分かるようになった」ら、いよいよ正確な情報を一次資料である公式ドキュメントから辿るタイミングです。
この流れは時として、公式ドキュメントと解説記事を行ったり来たりすることもあります。
それで大丈夫です。
そうして行ったり来たりする内に、「この解説記事は公式ドキュメントに書かれてないコマンドを使ってるけどなんなんだ?」とか、 「公式ドキュメントではこのコマンドが非推奨になってるけど、この解説記事では当たり前に使われてる」とか、 だんだん公式ドキュメントと解説記事の違いが分かるようになってきます。
そこまでくれば、「公式ドキュメントと解説記事の違い」「公式ドキュメントと目の前のシステムの違い」が否応なく目に付き始めます。
その違いはどこから来るかというと、バージョンやパッケージングの違いです。
パッケージングについては目の前のシステム = Linux ディストリビューションの流儀が大きく影響します。 そこで、前述のパッケージ管理ツールを使った調査テクニックが活躍するわけです。 公式ドキュメントで得られた知識を使って、目の前のシステムとの違いをパッケージ管理ツールで得られた情報で埋めていきます。 大抵は設定ファイルの場所が違ったり、追加の設定やスクリプトがあることが多いです。
もう一つ、バージョンの違いについてどう向き合えば良いでしょうか? 次のセクションでそれについてお話します。
ソフトウェアのバージョンに対してどこまで厳密に考えるか
バージョンが異なるドキュメントは役に立たないでしょうか?
そんなことはありません。 「目の前のもの全てがヒント」 はここにも適用されます。
バージョンが異なっても、「そのソフトウェアはそもそも何をするのか、どういう設定が必要なのか」という根幹部分まで変わることは滅多にありません。 つまりバージョンが異なるドキュメントや解説記事であっても、機能を表現する単語やキーワード、設定項目で使われる単語は別のバージョンでも使い回しが効きます。
他にも、古いバージョンの方が、その分解説記事がたくさん書かれていて、その中には非常に分かりやすく書かれたものもあるでしょう。 そうした記事で不変的な概念や設定項目を学んでおけば、新しいバージョンについて調べるときも応用が効きます。
また古いバージョンと新しいバージョンを比較する解説記事などを探すと「なぜその機能は変更されたのか」、「なぜその設定項目が追加/廃止されたのか」という解説も見つかったりします。 そうした情報は、ソフトウェアに対する理解をより一段と深めてくれます。
もちろん、最終的にシステムを設定する際の論拠とすべきは、そのシステムで使われているバージョンと一致するドキュメントであるのがベストです。
ただ、それに辿り着くための途中過程において、他のバージョンの資料で学ぶのは全く問題ないどころか大いに推奨できると筆者は考えています。
まとめ
本記事では man ページの解説に続き、ログ = システムの現在状況を確認するための各種コマンドと、ソフトウェア構成を調べるためのパッケージ管理ツールのコマンドを紹介しました。 また、それらを活用するときの心構えと、筆者の場合の調査技法も紹介しました。
しかし、効率面ではどうでしょうか?
manページを探したり、パッケージ構成を調べたり・・・そこまで調べる必要はあるのでしょうか?
雑誌記事や、検索して見つかった記事の内容をそのまま参考にしたほうが早くないでしょうか?
確かに、筆者のやり方は効率が悪いと思います。 単純に作業時間で見ると、書籍/雑誌/Web記事/動画/セミナー等で学んだり、その内容をそのまま適用する方が確かに早いです。 しかしそれは 「守破離」の3段階でいえば「守」の段階 だと考えます。
Linux システム全体に対する理解を深め、今目の前にある Linux のディストリビューションとバージョン、発生している課題に対してもっとも適切で安定した対応方法は何か、それを見つけ出すには 「破」の段階が必要 だと考えます。 現場の環境は「守」を学ぶときの環境とは異なり、学んだ内容をそのまま適用しようとするとエラーになったりうまく行かない、そのバージョンでは非推奨となったやり方だったりするからです。 そのような対応を進めてしまうと、長期的には別の不具合を誘発するなどしてシステムが不安定となります。
長期的に安定したシステムを構築するには、目の前の環境について理解を深め、自分の中でシステムの全体像を育て、時間がかかっても一つ一つのソフトウェアコンポーネントの位置づけや仕組み、関係性の理解を進めるのが、 短期的には遠回りだけど結果としては近道になる。 筆者はそのように考えています。
仮にエラーが起こったとしても、「なぜそのエラーが起きるのか?」を理解して、そのシステムにとって最も適切で安定した解決方法を探せるとベストです。 そのためには、そもそも「なぜそのコマンドでいいのか?」「なぜその設定ファイルをそのように書く必要があるのか?」こうした問にある程度答えられる必要があります。 つまりコマンドや設定ファイルの全体像、Linuxシステムにおける位置づけなど大局的なイメージを持っておく必要があると筆者は考えます。
こうしたイメージを育てるために、本記事では「ログの確認」と「パッケージ情報の調査」を紹介した次第です。
本記事が Linux 初心者や入門者、更には目の前のシステム上の課題に挑戦する実務者にとって、調査活動の一助になれば幸いです。
*1: man コマンド自体の manページを参照 = "man man" すると、解説されています。