获取进程的所有打开文件导致 errno 12 = Out of Memory

Getting all open files for process results in errno 12 = Out of Memory

在 SO 的帮助下,我编写了一个应用程序,显示 Swift 中所有打开的 TCP/UDP 连接。 在下一步中,我想获得打开连接的进程(几乎与 lsof 一样)。

由于 lsof 是开源的,我可以编写以下代码来获取进程的所有打开文件:

桥接头:

#include <mach/mach_types.h>
#include <mach/vm_param.h>
#include <mach/host_info.h>
#include <mach/task_info.h>
#include <mach/thread_info.h>
#include <mach/vm_region.h>
#include <libproc.h>

#include <sys/proc_info.h>
#include <sys/kdebug.h>
#include <sys/msgbuf.h>

(我认为不需要每个包含,但至少现在可以编译)。

for app in NSWorkspace.shared().runningApplications
    {
        let pid = app.processIdentifier

        var tai = proc_taskallinfo()
        let size = MemoryLayout<proc_bsdinfo>.size
        var result = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &tai, Int32(size))
        let fileCount: Int32 = Int32(tai.pbsd.pbi_nfiles)

        if result <= 0
        {
            if errno == ENOMEM
            {
                Swift.print("Out of memory.")
            }
            Swift.print(errno)
            continue
        }

        var fid = proc_fdinfo()
        let fdInfoSize = MemoryLayout<proc_fdinfo>.size
        result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, &fid, Int32(fdInfoSize) * fileCount)

        if result <= 0
        {
            Swift.print("Error. No Files?")
        }
        else
        {
            Swift.print("Files found.")
        }
    }

代码从 C 移植到 Swift 3. 原始 C 代码如下所示:

int nb;
struct proc_taskallinfo tai;
...  
nb = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &tai, sizeof(tai));

当我 运行 我的代码时,我得到错误号 12(内存不足)。为什么?

P.S。我知道第二个 proc_pidinfo 也会失败,因为返回的是指向 proc_fdinfo 数组的指针,而不是指向单个结构的指针,而是一次一个步骤。都是关于 errno 12.

有两个错误。首先,应该是

let size = MemoryLayout<proc_taskallinfo>.size

其次,proc_pidinfo(pid, PROC_PIDLISTFDS, ...)需要一个缓冲区 为 fileCount 类型的 proc_fdinfo 结构留出空间,而不仅仅是 一个:

var fid = Array(repeating: proc_fdinfo(), count: Int(fileCount))
let fdInfoSize = MemoryLayout<proc_fdinfo>.stride
result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, &fid, Int32(fdInfoSize) * fileCount)

这是获取 TCP 套接字的最终代码。不幸的是,无法在沙盒应用程序中使用该代码:

for app in NSWorkspace.shared().runningApplications {
    let pid = app.processIdentifier

    var tai = proc_taskallinfo()
    let size = MemoryLayout<proc_taskallinfo>.size
    var result = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &tai, Int32(size))
    let fileCount: Int32 = Int32(tai.pbsd.pbi_nfiles)

    if result <= 0 {
        continue
    }

    var fid = Array(repeating: proc_fdinfo(), count: Int(fileCount))
    let fdInfoSize = MemoryLayout<proc_fdinfo>.stride
    result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, &fid, Int32(fdInfoSize) * fileCount)

    if result <= 0 {
        Swift.print("Error PROC_PIDLISTFDS.")
    }
    else {
        for i in 0.. < Int(result) / fdInfoSize {
            let fdp = fid[i]

            if fdp.proc_fdtype == UInt32(PROX_FDTYPE_SOCKET) {
                var si = socket_fdinfo()
                let sizeSi = MemoryLayout<socket_fdinfo>.size
                result = proc_pidfdinfo(pid, fdp.proc_fd, PROC_PIDFDSOCKETINFO, &si, Int32(sizeSi))

                if result <= 0 {
                    Swift.print("Error PROC_PIDFDSOCKETINFO: " + errno.description)
                }
                else {
                    if si.psi.soi_kind == Int32(SOCKINFO_TCP) {
                        Swift.print("TCP Socket")
                    }
                }
            }
        }
    }
}