1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NetBSDカーネル内のstruct procからプロセスの親子関係をグラフ化してみる

Last updated at Posted at 2023-12-28

NetBSD Advent Calendar 2023 25日目の記事です。今日はカーネル内のプロセス情報からプロセスの親子関係のグラフを作成してみようと思います。

struct procに含まれているプロセス情報

NetBSDでのプロセスは/usr/src/sys/sys/proc.hで定義されている struct proc 構造体で管理されています。この構造体を見ると、struct proc->p_pptr を辿ることで親プロセスの情報を参照できるようです。そして char p_comm には実行しているコマンド名(=プロセス名)が入っているため、この2つの情報を参照することで、プロセスの親子関係をグラフ化できそうです。

230 struct proc {
...
265     struct proc     *p_pptr;    /* l: Pointer to parent process. */
...
335     char        p_comm[MAXCOMLEN+1];

さっそくカーネルモジュールを作成してみる

動作としては、ユーザ空間からread(2)した際にGraphvizのグラフとしてプロセスの親子関係を返すという形にしてみます。

サンプルコードは以下になります。

ユーザ空間側のread(2)に対応するカーネルモジュール側の関数は以下になります。

 93 int
 94 process_graph_sample_read(dev_t self __unused, struct uio *uio, int flags __unused)
 95 {
 96     int e;
 97     char result[4096] = { '\0' };
 98     char tmp[128] = { '\0' };
 99     char *r = result;
100
101     r = strcat(r, "digraph G {\n");
102
103     struct proc *p;
104     PROCLIST_FOREACH(p, &allproc) {
105         if (p->p_pid <= 1 || (p->p_flag & PK_SYSTEM) != 0) {
106             continue;
107         }
108         snprintf(tmp, 128, "\"%s\" -> \"%s\"", p->p_comm, p->p_pptr->p_comm);
109         r = strcat(r, tmp);
110         r = strcat(r, "\n");
111     }
112     r = strcat(r, "}\n");
113     r = strcat(r, "\0");
114
115     // 変数hostnameの値をユーザ空間にコピーする。
116     if ((e = uiomove(result, strlen(result), uio)))
117         return e;
118
119     return 0;
120 }

ポイントになる箇所…といっても特に何かあるワケではなく、以下の個所で親と子のプロセス名をdot形式のグラフ表記にしています。

108         snprintf(tmp, 128, "\"%s\" -> \"%s\"", p->p_comm, p->p_pptr->p_comm);

ユーザ空間側のコード

ユーザ空間からは単にread(2)するだけです。

実際に動かしてみる

# gcc -Wall -g -o process_graph_sample process_graph_sample.c
# ./process_graph_sample | tee output.dot
digraph G {
"sample" -> "bash"
"bash" -> "sshd"
"sshd" -> "sshd"
"getty" -> "init"
"getty" -> "init"
"getty" -> "init"
"getty" -> "init"
"cron" -> "init"
"inetd" -> "init"
"sshd" -> "init"
"powerd" -> "init"
"rpc.lockd" -> "init"
"rpc.statd" -> "init"
"rpcbind" -> "init"
"syslogd" -> "init"
"dhcpcd" -> "init"
}

PNG画像に変換します。

# dot -Tpng output.dot > output.png

output.png

プロセスの親子関係グラフが得られました。 inetddhcpcdsshd といったデーモンは init プロセスから生まれており、ユーザが利用するシェルは sshd から生まれていることが見て取れます。

まとめ

カーネル内のプロセス情報からプロセスの親子関係をグラフ化してみました。カーネルモジュール経由でカーネルの内部情報にアクセスする方法が把握できたので、今回のようなサンプル的なプログラムから一歩踏み込んだ実用的なツールやユーティリティ作成に応用できればと思います。

さいごに

今年も何とかNetBSD Advent Calendar 2023を完走することができました。これもひとえに皆様のおかげです。

@ryoon様、@oshimyja様、@ebijun様、@yamori813様(投稿日順です)ありがとうございました。

今年はAsiaBSDCon 2023も開催され、次期NetBSD-10に搭載される機能の紹介もあったことから、NetBSD-currentで来るべき新機能を調べたりしていました。wg(4)(WireGuard)を試してみたりしたかったのですが、ちょっと今回は調べる時間が足りませんでした。

とはいえ、今後もNetBSD-10のリリースまでは様々な機能の追加やバグ修正が行われるかと思いますので、来年はこまめにNetBSD情報を追いかけたり試したり、記事にしたりしてみようと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?