procs: 新しいプロセス表示・検索ツール（macOS対応＆機能追加）

# はじめに
以前、「[procs: 新しいプロセス表示・検索ツール](https://qiita.com/dalance/items/388d98c99ae2857d73e6)」という記事を書いたのですが、macOSで動かないの？という声が若干ありました。
手元にmacOSが動く実機がないので無理だと思っていましたが、Travis CIのWebコンソールで何となく動作確認出来そうだったので、ちまちまと作業を進めて一段落したので公開します。
基本的な紹介は上の記事を参照してください。

あといろいろと機能追加もあるのでそちらも紹介します。
最後にmacOS対応にあたってRustのプロセス情報取得クレートを一通り調べたので、その結果をまとめておきます。

# リポジトリ

https://github.com/dalance/procs/

Linux/macOS向けのバイナリは[Releases](https://github.com/dalance/procs/releases)からダウンロードするか、
Rustがインストール済みで`cargo`コマンドが使える方は以下でインストールできます。

```
$ cargo install procs
```

# macOS対応
一応今回の目玉ですが、先に書いた通り実機のターミナルで確認したことはないので、表示がとんでもないことになっている可能性はあります。
Travis CI上である程度値のチェック（`ps`と合っているか）はしたのでそれほど変な値は出さないと思います。
実機で使ってみて不具合がありましたら[GiuhubのIssue](https://github.com/dalance/procs/issues)でも、ここのコメントでもいいので教えて下さい。
出来る限り対応したいと思います。

あとmacOSではroot権限なしに他ユーザのプロセス情報を取れないようなので、SUIDを立てる必要があります。
（`ps`も立てているようです）

```
$ sudo chown root [procs binary path]
$ sudo chmod u+s [procs binary path]
```

# 新機能
## docker対応
プロセスがどのdockerコンテナに所属しているかを表示できます。

以下はdockerで[growi](https://growi.org)を立てたサーバで`procs growi`した結果です。
dockerコンテナ名もデフォルトで検索に引っかかるようにしているので、特定のコンテナのプロセスを探したいときに便利です。

![procs_docker.png](https://qiita-image-store.s3.amazonaws.com/0/84296/b391a694-2910-26ee-f290-eb7cb782e96e.png)

## pager対応
出力が端末サイズを越える場合に自動でpager（デフォルトでは`less`）を使用するようにしました。
また`less`の場合左右スクロールも効きます。

## カラムの拡充
`ps`コマンドで表示可能な情報はだいたい網羅しました。
`ps`では表示できない項目も主にメモリ周りでだいぶ増やしました。
macOS版は情報の取得方法が違うので、Linux版より少なくなっていますが、実用上はそれほど問題ないレベルと思います。

| procs `kind` | `ps` STANDARD FORMAT  | Description                      | Linux | macOS |
| ------------ | --------------------- | -------------------------------- | ----- | ----- |
| Command      | args                  | Command with all arguments       | o     | o     |
| ContextSw    | -not supported-       | Context switch count             | o     | o     |
| CpuTime      | cputime               | Cumulative CPU time              | o     | o     |
| Docker       | -not supported-       | Docker container name            | o     | o     |
| Eip          | eip                   | Instruction pointer              | o     |       |
| Esp          | esp                   | Stack pointer                    | o     |       |
| Gid          | egid                  | Group ID                         | o     | o     |
| GidFs        | fgid                  | File system group ID             | o     |       |
| GidReal      | rgid                  | Real group ID                    | o     | o     |
| GidSaved     | sgid                  | Saved group ID                   | o     | o     |
| Group        | egroup                | Group name                       | o     | o     |
| GroupFs      | fgroup                | File system group name           | o     |       |
| GroupReal    | rgroup                | Real group name                  | o     | o     |
| GroupSaved   | sgroup                | Saved group name                 | o     | o     |
| MajFlt       | maj_flt               | Major page fault count           | o     | o     |
| MinFlt       | min_flt               | Minor page fault count           | o     | o     |
| Nice         | ni                    | Nice value                       | o     | o     |
| Pid          | pid                   | Process ID                       | o     | o     |
| Policy       | policy                | Scheduling policy                | o     | o     |
| Ppid         | ppid                  | Parent process ID                | o     | o     |
| Priority     | pri                   | Priority                         | o     | o     |
| Processor    | psr                   | Currently assigned processor     | o     |       |
| ReadBytes    | -not supported-       | Read bytes from storage          | o     | o     |
| RtPriority   | rtprio                | Real-time priority               | o     |       |
| Separator    | -not supported-       | Show `｜` for column separation  | o     | o     |
| ShdPnd       | pending               | Pending signal mask for process  | o     |       |
| SigBlk       | blocked               | Blocked signal mask              | o     |       |
| SigCgt       | caught                | Caught signal mask               | o     |       |
| SigIgn       | ignored               | Ignored signal mask              | o     |       |
| SigPnd       | pending               | Pending signal mask for thread   | o     |       |
| StartTime    | start_time            | Starting time                    | o     | o     |
| State        | s                     | Process State                    | o     | o     |
| TcpPort      | -not supported-       | Bound TCP ports                  | o     | o     |
| Threads      | nlwp                  | Thread count                     | o     | o     |
| Tty          | tty                   | Controlling TTY                  | o     | o     |
| UdpPort      | -not supported-       | Bound UDP ports                  | o     | o     |
| Uid          | euid                  | User ID                          | o     | o     |
| UidFs        | fuid                  | File system user ID              | o     |       |
| UidReal      | ruid                  | Real user ID                     | o     | o     |
| UidSaved     | suid                  | Saved user ID                    | o     | o     |
| UsageCpu     | %cpu                  | CPU utilization                  | o     | o     |
| UsageMem     | %mem                  | Memory utilization               | o     | o     |
| User         | euser                 | User name                        | o     | o     |
| UserFs       | fuser                 | File system user name            | o     |       |
| UserReal     | ruser                 | Real user name                   | o     | o     |
| UserSaved    | suser                 | Saved user name                  | o     | o     |
| VmData       | -not supported-       | Data size                        | o     |       |
| VmExe        | trs                   | Text segments size               | o     |       |
| VmHwm        | -not supported-       | Peak resident set size           | o     |       |
| VmLib        | -not supported-       | Library code size                | o     |       |
| VmLock       | -not supported-       | Locked memory size               | o     |       |
| VmPeak       | -not supported-       | Peak virtual memory size         | o     |       |
| VmPin        | -not supported-       | Pinned memory size               | o     |       |
| VmPte        | -not supported-       | Page table entries size          | o     |       |
| VmRss        | rss                   | Resident set size                | o     | o     |
| VmSize       | vsz                   | Physical page size               | o     | o     |
| VmStack      | -not supported-       | Stack size                       | o     |       |
| VmSwap       | -not supported-       | Swapped-out virtual memory size  | o     |       |
| Wchan        | wchan                 | Process sleeping kernel function | o     |       |
| WriteByte    | -not supported-       | Write bytes to storage           | o     | o     |


# Rustのプロセス情報取得クレート

いろいろ調べた結果、Linux版はprocfs、macOS版はlibprocを使っていますが、採用しなかったクレート含めて状況（2019/2/22時点）を書いておきます。

## [procfs](https://crates.io/crates/procfs)

Linux版で使っているクレートで、`/proc`から情報取得します。
当初は`/proc/*/status`が取れないなど、若干機能不足だったのでPRを出して入れてもらいました。

## [procinfo](https://crates.io/crates/procinfo)

procfsと同じく`/proc`からの情報取得クレートです。
ダウンロード数も多くメジャーっぽいのですが、PIDの列挙ができなかったり
取れる情報が少なかったりで、こちらは採用しませんでした。

## [libproc](https://crates.io/crates/libproc)

macOS版で使っているクレートで、libprocの薄いラッパーになっています。
macOSやBSDには`/proc`がないので、プロセス情報は`sysctl`で取得することになります。
ただ、全部これで取得するのも大変ということか、プロセス情報を取得する高位のライブラリとして
libprocが提供されているようです。

こちらもいくつかのAPIが作りかけだったのでPRを出して入れてもらっているところです。
結構差分が多くて時間がかかりそうなので、現時点ではprocsのリポジトリ上に改変したライブラリを置いてリリースしました。
全ての差分が取り込まれたら、普通のライブラリ参照に戻す予定です。

## [sysctl](https://crates.io/crates/sysctl/)

macOS/BSD向けの`sysctl`ラッパーです。こちらも作りかけの感があり、組み込み型で返ってくるような呼び出しはできるのですが、配列で返ってくるものは取得不能のようでした。
そのため「最初に必要なPID一覧が得られない」という状況で、ここから全部作るのは大変すぎると思い、あきらめました。
どうしても`sysctl`が必要な部分は`libc::sysctl`を直接呼ぶことにしました。

## [sysinfo](https://crates.io/crates/sysinfo)

これはLinux/macOS/Windows/Raspberryに対応したシステム情報取得クレートです。
当初はこれ一本でいけるかとも思ったのですが、マルチプラットフォームにする関係上、どのプラットフォームでも取得できる内容にならざるを得ず、かなり情報が足りなくてあきらめました。
ただ、macOS版の一部の情報（libprocで取れないもの）はここのソースコードが参考になりました。