5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

libprocps programming

Last updated at Posted at 2016-12-29

いきなり結論

プロセスを巡回したい場合

readproc.c
#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を入れて実行する例。

get_proc_stats.c
#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を使うのがよい。

libprocpsprocps-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記法になれるにはもう少し時間がかかりそう。次回以降の記事はどうするかは未定。

5
2
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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?