使用しているファイルの一覧を取得する
プロセスが使用しているファイルの一覧を取得する。
「c - on iOS/iPhone: "Too many open files": need to list open files (like lsof) - Stack Overflow」によると、fcntlでfdを舐めてパスを取れば良いっぽい。
#include <sys/param.h> #include <sys/fcntl.h> void show_openfiles() { int flags; int fd; char buf[MAXPATHLEN + 1] ; for (fd = 0; fd < OPEN_MAX; fd++) { errno = 0; flags = fcntl(fd, F_GETPATH, buf); if (flags != -1) { printf("File Descriptor %d in use for: %s\n", fd, buf) ; } } }
なんか適当にファイルを開いた状態で読んでみる。
id filehandle = [NSFileHandle fileHandleForReadingAtPath:@"/etc/services"]; show_openfiles(); ...
出力
File Descriptor 0 in use for: /dev/null File Descriptor 1 in use for: /dev/ttys000 File Descriptor 2 in use for: /dev/ttys000 File Descriptor 3 in use for: /private/etc/services
0〜2は標準入力、標準出力、標準エラー出力。/dev/ttys...になっているのはソケットの模様。
sysctlでKERN_FILEを取れないかやってみた。
#include <sys/sysctl.h> #include <sys/file.h> /* file types */ typedef enum { DTYPE_VNODE = 1, /* file */ DTYPE_SOCKET, /* communications endpoint */ DTYPE_PSXSHM, /* POSIX Shared memory */ DTYPE_PSXSEM, /* POSIX Semaphores */ DTYPE_KQUEUE, /* kqueue */ DTYPE_PIPE, /* pipe */ DTYPE_FSEVENTS, /* fsevents */ DTYPE_MAX } file_type_t; #define DTYPE_NAME { \ "*UNKNOWN*", \ "DTYPE_VNODE", \ "DTYPE_SOCKET", \ "DTYPE_PSXSHM", \ "DTYPE_PSXSEM", \ "DTYPE_KQUEUE", \ "DTYPE_PIPE", \ "DTYPE_FSEVENTS" \ } LIST_HEAD(filelist, extern_file); void show_kernfiles(void) { int count[DTYPE_MAX]; for (int i = 0; i < DTYPE_MAX; i++) count[i] = 0; const char *dtype_name[] = DTYPE_NAME; size_t size; if (sysctlbyname("kern.file", NULL, &size, NULL, 0) == -1) { perror("sysctl: kern.file"); return; } char *buffer = malloc(size); if (sysctlbyname("kern.file", buffer, &size, NULL, 0) == -1) { perror("sysctl: kern.file"); return; } char *ptr = buffer; struct filelist filehead = *(struct filelist *)ptr; ptr += sizeof(struct filelist); struct extern_file *fp; for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next){ fp = (struct extern_file *)ptr; printf("fp = %p\n", fp); printf("f_list.le_next = %p\n", fp->f_list.le_next); printf("f_flag = %x\n", fp->f_flag); printf("f_type = %d\n", fp->f_type); printf("f_count = %d\n", fp->f_count); printf("f_msgcount = %d\n", fp->f_msgcount); printf("f_cred = %p\n", fp->f_cred); printf("f_ops = %p\n", fp->f_ops); printf("f_offset = %lld\n", fp->f_offset); printf("f_data = %p\n", fp->f_data); if (fp->f_type >= DTYPE_VNODE && fp->f_type < DTYPE_MAX) { count[fp->f_type]++;; } else { printf("unknown type = %d\n", fp->f_type); count[0]++;; } ptr += sizeof(struct extern_file); } free(buffer); printf("\nSummary:\n"); for (int i = 0; i < DTYPE_MAX; i++) { printf("\t%s:\t%d\n", dtype_name[i], count[i]); } }
file_type_tは定義が見つからなかったからxnuのソースコードの新しそうな奴から持って来た。
取得したデータの中身はsys/sysctl.hによると「struct: file entries」らしいのだが、具体的には何か分からないし、データの中身を見ると36バイト周期っぽかったので多分struct extern_fileと思う。
struct extern_fileはLIST_ENTRYでリンク構造になっているのでLIST_HEADで先頭のポインタの型を作ってやる。
但し、リンクの中身はカーネル空間のアドレス(0x80000000以降)で見れないので、そっちは使わずに構造体のサイズ分をポインタを進めている。
出力:
fp = 0xe07de04 f_list.le_next = 0x9880a900 f_flag = 1 f_type = 1 f_count = 41 f_msgcount = 0 f_cred = 0x80b52f80 f_ops = 0x802c4168 f_offset = 0 f_data = 0x81e875c8 ... fp = 0xe080df8 f_list.le_next = 0x0 f_flag = 1 f_type = 1 f_count = 28 f_msgcount = 0 f_cred = 0x80b52f80 f_ops = 0x802c4168 f_offset = 0 f_data = 0x81e875c8 Summary: *UNKNOWN*: 0 DTYPE_VNODE: 144 DTYPE_SOCKET: 145 DTYPE_PSXSHM: 0 DTYPE_PSXSEM: 0 DTYPE_KQUEUE: 36 DTYPE_PIPE: 16 DTYPE_FSEVENTS: 1
VNODEというのがファイルのようで、実際にf_dataの中身にアクセス出来ればパス等も取れそうだけど、檻の中からカーネルタスクのメモリに自由にアクセスする方法がないので詳細は見られないっぽい。
kern.vnodeも読んでみたけど、こっちはEINVALになって内容は読めなかった。