いきなり結論
プロセスを巡回したい場合
#include <stdio.h>
#include <proc/readproc.h>
static void show_proc(proc_t *proc_info) {
printf ("tid=%d, ppid=%d, pgrp=%d, session=%d, tty=%d, tpgid=%d [%s]\n",
proc_info->tid, proc_info->ppid,proc_info->pgrp, proc_info->session,
proc_info->tty, proc_info->tpgid,
proc_info->cmd);
return;
}
int main(int argc, char* argv[]){
PROCTAB* proc;
proc_t *proc_info;
proc = openproc(PROC_FILLARG | PROC_FILLSTAT);
if (proc == NULL) {
fprintf (stderr, "openproc fail\n");
return 1;
}
while ( (proc_info=readproc(proc, NULL)) != NULL) {
show_proc (proc_info);
freeproc(proc_info);
}
closeproc(proc);
return 0;
}
特定プロセス情報を得たい場合
1つ以上の引数としてPIDを入れて実行する例。
#include <stdio.h>
#include <stdlib.h>
#include <proc/readproc.h>
static void show_proc(proc_t *proc_info) {
printf ("tid=%d, ppid=%d, pgrp=%d, session=%d, tty=%d, tpgid=%d [%s]\n",
proc_info->tid, proc_info->ppid,proc_info->pgrp, proc_info->session,
proc_info->tty, proc_info->tpgid,
proc_info->cmd);
return;
}
int main(int argc, char* argv[]){
int i;
pid_t pid;
PROCTAB* proc;
proc_t *proc_info;
if (argc < 2) {
fprintf (stderr, "argument required PIDs\n");
return 1;
}
for( i=1; i<argc; i++) {
pid = atoi (argv[i]);
proc = openproc(PROC_FILLARG | PROC_FILLSTAT | PROC_PID, &pid);
if (proc == NULL) {
fprintf (stderr, "openproc fail with PID %d\n", pid);
continue;
}
while ( (proc_info=readproc(proc, NULL)) != NULL) {
show_proc (proc_info);
freeproc(proc_info);
}
closeproc(proc);
}
return 0;
}
確認環境
確認環境はgcc-4.9, Linux-3.10, aarch64, procps-ng-3.3.10くらいだったはず。
はじめに
Linuxでプロセスの情報を得たい場合、procfs(5)の**/proc/[pid]/にあるstat**,statm,statusを見ればいい。が、パースするのが意外とめんどい。何番目が何かとか覚えたくもない。Linuxバージョン違いで取得できる数の違いも気にしたくない。そういうときはlibprocpsを使うのがよい。
libprocpsはprocps-ng(もしくはfork元のprocps)が提供するライブラリ、つまりps,free,vmstat,topといったコマンド群を提供しているパッケージの一部。readelf -dしてもらえばわかるが、これらコマンドもlibprocpsを使っている。なので、いつメンテが止まったりAPIが変わったり...な心配はたぶんない。
procps-ngについての詳細は、Linux From ScratchもしくはGithubあたりに行くとよい。
注意点
APIの確認
広く使われている割には、manくらいしかろくなドキュメントはない模様。(manさえあれば十分?) ググってサンプルプログラムを探すよりも、/usr/include/proc/readproc.h
を開いて直接enumとかを確認した方が手っ取り早い。
メモリリーク注意
freeprocを呼ぶのを忘れがち。Stack Overflowにズバリのページがあるので確認しておこう。
get_proc_stats問題
proc/readproc.hを見るとget_proc_statsという関数があり使えるかのように見えるが、コンパイルするとundefined referenceでリンクエラーになる。private symbolに変わったのが原因。リンク先参考にprocps-ngを変更してコンパイルすれば使えるようになるが、使ってほしくないからprivate symbolに変わったわけで、使わないに越したことはない。このため上記サンプルプログラムはopenprocの引数を使ったものとしている。
kernel threadかどうかの確認
psを実行するとkernel threadは**[procname]**と大括弧付きの表記になるが、これをどこで判定しているかわからなかった。「session==0 または pgrp==0 ならば kernel thread」でいいように見える。daemonがあるので「tty==0」では判断してはいけない。
2017/03/29(Wed)追記、psは[proc_name]にするかどうかを「/proc/[PID]/cmdlineからreadして1バイト以上読めたかどうか」で判定する。ESC_BRACKETSのフラグで検索すればわかる。必ずしもkernel threadに限らないことも含め、このへんに詳しい。...でもfork中やexec中って/proc/[PID]/cmdlineって読めなくなるんだったっけ?
ソースを読む場合
パッケージの中に**HACKING**というファイルがあり、中の設計の簡単な解説があるので、先にこちらを確認するとよい。
あとがき1
特定プロセスのプロセスグループIDを確認したくてlibprocpsを調べたわけだが、**getpgid(2)を使うだけでよかった...他人のプロセスであろうが、/proc/[pid]/やgetpgid(2)**を使うのに特に権限は必要ないようだった。組み込み畑で育ったもので、権限管理については疎い...
あとがき2
普段は自分のサイトのブログに記事を書くけど、最近Qiitaがいいらしいと聞いて登録して使い始めてみたので、せっかくなのでこっちで書いてみた。Qiita記法になれるにはもう少し時間がかかりそう。次回以降の記事はどうするかは未定。