#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/sysctl.h>
typedef struct kinfo_proc kinfo_proc;
static int GetBSDProcessList(kinfo_proc **procList, size_t *procCount)
// システム上のすべての BSD プロセスのリストを返す
// このルーチンは、このリストの割り当てを行って *procList に入れ
// エントリの数を *procCount に返す
// このリストは自分で解放しなければならない(System フレームワークの free を使用)
// 成功時、関数は 0 を返す
// エラー発生時には、関数は BSD の errno の値を返す
{
int err;
kinfo_proc * result;
bool done;
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
// name を const として宣言するので、sysctl に渡すときにキャストする必要がある
// プロトタイプに const が含まれていないからだ
size_t length;
assert( procList != NULL);
assert(*procList == NULL);
assert(procCount != NULL);
*procCount = 0;
// result == NULL と length == 0 として sysctl を呼び出すことにより開始。
// これは成功し、length が適切な長さに設定される。
// その後そのサイズのバッファを割り当て、sysctl を再び呼び出す
// これが成功すれば処理は終了である。ENOMEM エラーで失敗した場合は
// バッファを破棄してループする必要がある。
// このループでは、再び NULL を指定して、sysctl を呼び出す必要があることに注意。
// これは必要な処理である。ENOMEM エラーの場合、length は、
// 返されるべきデータ量ではなく
// 返されたデータ量に設定されるからだ
result = NULL;
done = false;
do {
assert(result == NULL);
// バッファを NULL にして sysctl を呼び出す
length = 0;
err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
NULL, &length,
NULL, 0);
if (err == -1) {
err = errno;
}
// 上記の呼び出しの結果に基づき適切なサイズの
// バッファを割り当てる
if (err == 0) {
result = malloc(length);
if (result == NULL) {
err = ENOMEM;
}
}
// この新しいバッファを使って sysctl を再び呼び出す
// ENOMEM エラーを受け取った場合は、バッファを破棄しもう一度やり直す
if (err == 0) {
err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
result, &length,
NULL, 0);
if (err == -1) {
err = errno;
}
if (err == 0) {
done = true;
} else if (err == ENOMEM) {
assert(result != NULL);
free(result);
result = NULL;
err = 0;
}
}
} while (err == 0 && ! done);
// クリーンナップ処理を行い、事後状態を設定する
if (err != 0 && result != NULL) {
free(result);
result = NULL;
}
*procList = result;
if (err == 0) {
*procCount = length / sizeof(kinfo_proc);
}
assert( (err == 0) == (*procList != NULL) );
return err;
}
|