hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

lsofコマンドの使い方



1 lsofコマンドとは?

ファイルをオープンしているプロセスを表示するコマンドです

2 検証環境

CentOS版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
3.10.0-1160.el7.x86_64

3 インストール方法

lsofパッケージをインストールします。

[root@server ~]# yum -y install lsof

lsof コマンドの版数を確認します。

[root@server ~]# lsof -v
lsof version information:
    revision: 4.87

4 オプション一覧

[root@server ~]# lsof -h
lsof 4.87
 latest revision: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
 latest FAQ: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
 latest man page: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof_man
 usage: [-?abhKlnNoOPRtUvVX] [+|-c c] [+|-d s] [+D D] [+|-f[gG]] [+|-e s]
 [-F [f]] [-g [s]] [-i [i]] [+|-L [l]] [+m [m]] [+|-M] [-o [o]] [-p s]
[+|-r [t]] [-s [p:s]] [-S [t]] [-T [t]] [-u s] [+|-w] [-x [fl]] [-Z [Z]] [--] [names]
Defaults in parentheses; comma-separated set (s) items; dash-separated ranges.
  -?|-h list help          -a AND selections (OR)     -b avoid kernel blocks
  -c c  cmd c ^c /c/[bix]  +c w  COMMAND width (9)    +d s  dir s files
  -d s  select by FD set   +D D  dir D tree *SLOW?*   +|-e s  exempt s *RISKY*
  -i select IPv[46] files  -K list tasKs (threads)    -l list UID numbers
  -n no host names         -N select NFS files        -o list file offset
  -O no overhead *RISKY*   -P no port names           -R list paRent PID
  -s list file size        -t terse listing           -T disable TCP/TPI info
  -U select Unix socket    -v list version info       -V verbose search
  +|-w  Warnings (+)       -X skip TCP&UDP* files     -Z Z  context [Z]
  -- end option scan
  +f|-f  +filesystem or -file names     +|-f[gG] flaGs
  -F [f] select fields; -F? for help
  +|-L [l] list (+) suppress (-) link counts < l (0 = all; default = 0)
                                        +m [m] use|create mount supplement
  +|-M   portMap registration (-)       -o o   o 0t offset digits (8)
  -p s   exclude(^)|select PIDs         -S [t] t second stat timeout (15)
  -T qs TCP/TPI Q,St (s) info
  -g [s] exclude(^)|select and print process group IDs
  -i i   select by IPv[46] address: [46][proto][@host|addr][:svc_list|port_list]
  +|-r [t[m<fmt>]] repeat every t seconds (15);  + until no files, - forever.
       An optional suffix to t is m<fmt>; m must separate t from <fmt> and
      <fmt> is an strftime(3) format for the marker line.
  -s p:s  exclude(^)|select protocol (p = TCP|UDP) states by name(s).
  -u s   exclude(^)|select login|UID set s
  -x [fl] cross over +d|+D File systems or symbolic Links
  names  select named files or files on named file systems
Anyone can list all files; /dev warnings disabled; kernel ID check disabled.

5 ファイルをオープンしているプロセスを調べる方法

5.1 基本的な使い方

/var/log/messagesファイルに対して、lsofコマンドを実行してみます。 abrt-watch-logとrsyslogdの2つのプロセスが/var/log/messagesファイルをオープンしていることがわかります。 なお、プロセス名(COMMAND)の長さは、デフォルトで9文字です。そのため、abrt-watch-logがabrt-watcと切り詰められています。

[root@server ~]# lsof /var/log/messages
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
abrt-watc  643 root    4r   REG    8,3   330928 16878700 /var/log/messages
rsyslogd  1074 root    4w   REG    8,3   330928 16878700 /var/log/messages

次に、rsyslogサービスを停止します。

[root@server ~]# systemctl stop rsyslog.service

再度、lsofコマンドを実行します。 rsyslogdプロセスは、/var/log/messagesをオープンしていないことがわかります。

[root@server ~]# lsof /var/log/messages
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
abrt-watc 643 root    4r   REG    8,3   330928 16878700 /var/log/messages

5.2 ディレクトリを再帰的にたどる方法(+D)

+Dオプションを指定すると、指定したディレクト配下を再帰的にたどり、ファイルをオープンしているプロセスを表示します。

[root@server ~]# lsof +D /var/log/
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
auditd     598 root    5w   REG    8,3  2245418 33584848 /var/log/audit/audit.log
abrt-watc  643 root    4r   REG    8,3   337295 16878700 /var/log/messages
firewalld  745 root    3w   REG    8,3     6449 17913092 /var/log/firewalld
tuned     1073 root    3w   REG    8,3    16740 51319417 /var/log/tuned/tuned.log
cupsd     1079 root    6u   REG    8,3        0 51184781 /var/log/cups/access_log
cupsd     1079 root    7u   REG    8,3        0 51184782 /var/log/cups/error_log
cupsd     1079 root    8u   REG    8,3        0 51184783 /var/log/cups/page_log
rsyslogd  3327 root    6w   REG    8,3   337295 16878700 /var/log/messages
rsyslogd  3327 root    7w   REG    8,3     5134 16878701 /var/log/secure
rsyslogd  3327 root    8w   REG    8,3     4706 16878698 /var/log/cron

5.3 ディレクトリを再帰的にたどらない方法(+d)

+dオプションを指定すると、指定したディレクトに存在するファイルをオープンしているプロセスを表示します。

[root@server ~]# lsof +d /var/log/
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
abrt-watc  643 root    4r   REG    8,3   337499 16878700 /var/log/messages
firewalld  745 root    3w   REG    8,3     6449 17913092 /var/log/firewalld
rsyslogd  3327 root    6w   REG    8,3   337499 16878700 /var/log/messages
rsyslogd  3327 root    7w   REG    8,3     5134 16878701 /var/log/secure
rsyslogd  3327 root    8w   REG    8,3     4706 16878698 /var/log/cron

6 オープンしているファイルをユーザで絞り込む方法(-u)

6.1 特定のユーザが使用しているファイルを表示する方法

chronyユーザがオープンしているファイルを表示してみます。

[root@server ~]# lsof -u chrony
COMMAND PID   USER   FD   TYPE             DEVICE SIZE/OFF    NODE NAME
chronyd 667 chrony  cwd    DIR                8,3      264      64 /
chronyd 667 chrony  rtd    DIR                8,3      264      64 /
chronyd 667 chrony  txt    REG                8,3   269392  461392 /usr/sbin/chronyd
-snip-

次に、polkitdユーザがオープンしているファイルを表示してみます。

[root@server ~]# lsof -u polkitd
COMMAND PID    USER   FD      TYPE             DEVICE SIZE/OFF     NODE NAME
polkitd 627 polkitd  cwd       DIR                8,3      264       64 /
polkitd 627 polkitd  rtd       DIR                8,3      264       64 /
polkitd 627 polkitd  txt       REG                8,3   120432 34158507 /usr/lib/polkit-1/polkitd
-snip-

6.2 特定のユーザ以外のユーザが使用しているファイルを表示する方法

rootユーザ以外のユーザがオープンしているファイルを表示してみます。

[root@server ~]# lsof -u ^root
COMMAND    PID TID           USER   FD      TYPE             DEVICE SIZE/OFF     NODE NAME
lsmd       625     libstoragemgmt  cwd       DIR                8,3      264       64 /
lsmd       625     libstoragemgmt  rtd       DIR                8,3      264       64 /
lsmd       625     libstoragemgmt  txt       REG                8,3    24016 56028264 /usr/bin/lsmd
-snip-

7 オープンしているファイルをFDで絞り込む方法

chronyユーザがオープンしているファイルの中で、FD=8のファイルを表示してみます。 -uでユーザを指定し、-dでFD(File Descriptor)を指定します。-aは-uと-dのAND条件を指定するために使用しています。 lsofの実行結果より、chronyユーザは、/var/run/chrony/chronyd.sockをFD=8でオープンしていることがわかります。

[root@server ~]#  lsof -u chrony -a -d 8
COMMAND PID   USER   FD   TYPE             DEVICE SIZE/OFF  NODE NAME
chronyd 667 chrony    8u  unix 0xffff9e0bf5790440      0t0 20186 /var/run/chrony/chronyd.sock

8 プロセス名の表示幅を広げる方法(+c)

lsofの実行結果に表示されるプロセス名(COMMAND)の幅はデフォルトで9文字です。 +cオプションを指定することで、幅を広げることができます。

+c0を指定すると、プロセス名が途中で切り捨てられることなく全て表示されます。

[root@server ~]# lsof +c0 /var/log/messages
COMMAND         PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
abrt-watch-log  643 root    4r   REG    8,3   340736 16878700 /var/log/messages
rsyslogd       3327 root    6w   REG    8,3   340736 16878700 /var/log/messages

次に、+c10を指定してみます。 abrt-watch-logプロセス名がデフォルト表示のabrt-watcからabrt-watchに1文字多く表示されるようになったことがわかります。

[root@server ~]# lsof +c10 /var/log/messages
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
abrt-watch  643 root    4r   REG    8,3   340869 16878700 /var/log/messages
rsyslogd   3327 root    6w   REG    8,3   340869 16878700 /var/log/messages

9 INETドメインソケットに関する使いかた

9.1 IPV4,IPv6ソケットを使用しているプロセスを絞り込む方法(-i)

-iオプションを使うと、IPV4,IPv6ソケットを使用しているプロセスを表示できます。 rpcbindプロセスは、IPV4,IPv6ソケットを使用していることがわかります。

[root@server ~]# lsof -i
COMMAND    PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rpcbind    624    rpc    6u  IPv4  19549      0t0  UDP *:sunrpc
rpcbind    624    rpc    7u  IPv4  19550      0t0  UDP *:798
rpcbind    624    rpc    8u  IPv4  19551      0t0  TCP *:sunrpc (LISTEN)
rpcbind    624    rpc    9u  IPv6  19552      0t0  UDP *:sunrpc
rpcbind    624    rpc   10u  IPv6  19553      0t0  UDP *:798
rpcbind    624    rpc   11u  IPv6  19554      0t0  TCP *:sunrpc (LISTEN)
-snip-

9.2 TCPソケットを使用しているプロセスを絞り込む方法(-i)

-iまたはiTCPとオプションを指定することで、TCPのソケットを使用しているプロセスを表示することができます。

[root@server ~]# lsof -iTCP
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rpcbind  624    rpc    8u  IPv4  19551      0t0  TCP *:sunrpc (LISTEN)
rpcbind  624    rpc   11u  IPv6  19554      0t0  TCP *:sunrpc (LISTEN)
sshd    1040   root    3u  IPv4  25400      0t0  TCP *:ssh (LISTEN)
sshd    1040   root    4u  IPv6  25402      0t0  TCP *:ssh (LISTEN)
cupsd   1043   root   10u  IPv6  25413      0t0  TCP localhost:ipp (LISTEN)
cupsd   1043   root   11u  IPv4  25414      0t0  TCP localhost:ipp (LISTEN)
master  1344   root   13u  IPv4  27774      0t0  TCP localhost:smtp (LISTEN)
master  1344   root   14u  IPv6  27775      0t0  TCP localhost:smtp (LISTEN)
dnsmasq 1399 nobody    6u  IPv4  23540      0t0  TCP server:domain (LISTEN)
sshd    1708   root    3u  IPv4  28102      0t0  TCP server:ssh->DESKTOP-MB6G4KI:53893 (ESTABLISHED)

9.3 UDPソケットを使用しているプロセスを絞り込む方法(-iUDP)

-iUDPとオプションを指定することで、UDPのソケットを使用しているプロセスを表示することができます。

[root@server ~]# lsof -iUDP
COMMAND    PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rpcbind    624    rpc    6u  IPv4  19549      0t0  UDP *:sunrpc
rpcbind    624    rpc    7u  IPv4  19550      0t0  UDP *:798
rpcbind    624    rpc    9u  IPv6  19552      0t0  UDP *:sunrpc
rpcbind    624    rpc   10u  IPv6  19553      0t0  UDP *:798
avahi-dae  647  avahi   12u  IPv4  20389      0t0  UDP *:mdns
avahi-dae  647  avahi   13u  IPv4  20390      0t0  UDP *:51640
chronyd    678 chrony    5u  IPv4  23578      0t0  UDP localhost:323
chronyd    678 chrony    6u  IPv6  23579      0t0  UDP localhost:323
dhclient   849   root    6u  IPv4  22863      0t0  UDP *:bootpc
dnsmasq   1399 nobody    3u  IPv4  23536      0t0  UDP *:bootps
dnsmasq   1399 nobody    5u  IPv4  23539      0t0  UDP server:domain

9.4 ポート番号で使用しているプロセスを絞り込む方法

TCPの22番ポートを使用しているプロセスを表示してます。 sshdプロセスがTCPの22番ポートを使用していることがわかります。 なお、-Pオプションを指定すると、sshのようなサービス名ではなくポート番号を表示することができます。

[root@server ~]# lsof -i:22 -P
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1092 root    3u  IPv4  27698      0t0  TCP *:22 (LISTEN)
sshd    1092 root    4u  IPv6  27700      0t0  TCP *:22 (LISTEN)
sshd    1801 root    3u  IPv4  28373      0t0  TCP server:22->DESKTOP-MB6G4KI:60395 (ESTABLISHED)

ポート番号の範囲を指定することもできます。 TCPの1番ポートから50番ポートを使用しているプロセスを表示してみます。

[root@server ~]# lsof -i:1-50 -P
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1092 root    3u  IPv4  27698      0t0  TCP *:22 (LISTEN)
sshd    1092 root    4u  IPv6  27700      0t0  TCP *:22 (LISTEN)
master  1309 root   13u  IPv4  28815      0t0  TCP localhost:25 (LISTEN)
master  1309 root   14u  IPv6  28816      0t0  TCP localhost:25 (LISTEN)
sshd    1801 root    3u  IPv4  28373      0t0  TCP server:22->DESKTOP-MB6G4KI:60395 (ESTABLISHED)

9.5 IPアドレスでプロセスを絞り込む方法

[root@server ~]# lsof -i@192.168.2.100 -n
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1801 root    3u  IPv4  28373      0t0  TCP 192.168.2.100:ssh->192.168.2.12:60395 (ESTABLISHED)

9.6 TCPの状態でプロセスを絞り込む方法

TCPの状態がESTABLISHEDのプロセスを表示してみます。

[root@server ~]# lsof -i -sTCP:ESTABLISHED -n
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1801 root    3u  IPv4  28373      0t0  TCP 192.168.2.100:ssh->192.168.2.12:60395 (ESTABLISHED)

次は、TCPの状態がLISTENのプロセスを表示してみます。

[root@server ~]# lsof -i -sTCP:LISTEN -n
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rpcbind  647    rpc    8u  IPv4  20029      0t0  TCP *:sunrpc (LISTEN)
rpcbind  647    rpc   11u  IPv6  20032      0t0  TCP *:sunrpc (LISTEN)
cupsd   1085   root   10u  IPv6  28744      0t0  TCP [::1]:ipp (LISTEN)
cupsd   1085   root   11u  IPv4  28745      0t0  TCP 127.0.0.1:ipp (LISTEN)
sshd    1092   root    3u  IPv4  27698      0t0  TCP *:ssh (LISTEN)
sshd    1092   root    4u  IPv6  27700      0t0  TCP *:ssh (LISTEN)
master  1309   root   13u  IPv4  28815      0t0  TCP 127.0.0.1:smtp (LISTEN)
master  1309   root   14u  IPv6  28816      0t0  TCP [::1]:smtp (LISTEN)
dnsmasq 1714 nobody    6u  IPv4  28089      0t0  TCP 192.168.122.1:domain (LISTEN)

10 リピートモードの使い方

ncプロセス(-c)が使用するINETドメイン(-i)のソケットを2秒間隔(-r2)で監視してみます。 -mはマーカです。%Tは時刻を表示します。 また、-aオプションを使って3つの条件をAND条件で指定しています。

lsofコマンドを実行します。 なお、ncコマンドの使い方は、ncコマンドの使い方(ネットワーク実験の幅が広がるなぁ~) - hana_shinのLinux技術ブログを参照してくだい。

[root@server ~]# lsof -c nc -a -i4 -a -P -a -r2m====%T====
====17:06:14====
====17:06:16====

もう1つターミナルを開きます。そしてncコマンドを実行します。

[root@server ~]# nc -kl 11111

lsofコマンドの実行結果を確認します。 ncプロセスのTCPの状態がLISTENになったことがわかります。

[root@server ~]# lsof -c nc -a -i4 -a -P -a -r2m====%T====
====17:08:50====
====17:08:52====
====17:08:54====
====17:08:56====
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      3500 root    4u  IPv4  46030      0t0  TCP *:11111 (LISTEN)
====17:08:58====
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      3500 root    4u  IPv4  46030      0t0  TCP *:11111 (LISTEN)
-snip-

クライアントでncコマンドを実行します。

[root@client ~]# nc 192.168.2.100 11111

lsofコマンドの実行結果を確認します。 ncプロセスのTCPの状態がLISTENからESTABLISHEDになったことがわかります。

[root@server ~]# lsof -c nc -a -i4 -a -P -a -r2m====%T====
-snip-
====17:11:25====
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      3500 root    4u  IPv4  46030      0t0  TCP *:11111 (LISTEN)
nc      3500 root    5u  IPv4  56384      0t0  TCP server:11111->client:43798 (ESTABLISHED)

11 ソケットの状態を表示する方法

IPv4TCPソケットの情報を表示してみます。

[root@server ~]# lsof -i4TCP -Tqs
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rpcbind  647    rpc    8u  IPv4  20029      0t0  TCP *:sunrpc (LISTEN QR=0 QS=0)
cupsd   1085   root   11u  IPv4  28745      0t0  TCP localhost:ipp (LISTEN QR=0 QS=0)
sshd    1092   root    3u  IPv4  27698      0t0  TCP *:ssh (LISTEN QR=0 QS=0)
master  1309   root   13u  IPv4  28815      0t0  TCP localhost:smtp (LISTEN QR=0 QS=0)
dnsmasq 1714 nobody    6u  IPv4  28089      0t0  TCP server:domain (LISTEN QR=0 QS=0)
sshd    1801   root    3u  IPv4  28373      0t0  TCP server:ssh->DESKTOP-MB6G4KI:60395 (ESTABLISHED QR=0 QS=36)

なお、上記実行結果中のQR、QSの意味は以下のとおりです。

QRカーネル受信バッファに存在する受信データのバイト数。ユーザプロセスがまだ読み出していない受信データです。

QS:カーネル送信バッファに存在する送信データのバイト数。まだACKを受信しておらず、開放されていない送信データです。

QRについて、以下のような実験をして確認してみます。 まず、サーバでncコマンドを実行します。

[root@server ~]# nc -kl 11111

lsofコマンドを実行します。QRの値は0であることがわかります。

[root@server ~]#  lsof -c nc -i4TCP -a -P -a -Tqs
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      3683 root    4u  IPv4  56710      0t0  TCP *:11111 (LISTEN QR=0 QS=0)

クライアントでncコマンドを実行します。 ncコマンドを実行すると、サーバのncプロセスとの間でTCPコネクションが確立されます。

[root@client ~]# nc 192.168.2.100 11111

サーバでCtrl+zを押下して、ncプロセスを停止します。

[root@server ~]# nc -kl 11111
^Z
[1]+  停止                  nc -kl 11111

クライアントで12345と入力します。改行コードも含めて6バイトがサーバに送信されます。

[root@client ~]# nc 192.168.2.100 11111
12345

lsofコマンドを実行します。QRの値が6になったことがわかります。

[root@server ~]#  lsof -c nc -i4TCP -a -P -a -Tqs
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      3683 root    4u  IPv4  56710      0t0  TCP *:11111 (LISTEN QR=0 QS=0)
nc      3683 root    5u  IPv4  58859      0t0  TCP server:11111->client:43806 (ESTABLISHED QR=6 QS=0)

次にfgコマンドを実行して、サーバのncプロセスを再開します。 ncプロセスが再開すると、カーネルの受信バッファから受信データを読み出します。

[root@server ~]# fg
nc -kl 11111
12345

再度、lsofコマンドを実行します。QRの値が0になったことがわかります。 これは、ncプロセスを再開したことで、ncプロセスがカーネル受信バッファにたまっていた6バイトのデータを読み出したからです。

[root@server ~]#  lsof -c nc -i4TCP -a -P -a -Tqs
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      3683 root    4u  IPv4  56710      0t0  TCP *:11111 (LISTEN QR=0 QS=0)
nc      3683 root    5u  IPv4  58859      0t0  TCP server:11111->client:43806 (ESTABLISHED QR=0 QS=0)

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。 Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ