Search code examples
swifterrnolsof

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


With the help of SO, I wrote an app that displays all open TCP/UDP connections in Swift. In the next step, I would like to get the process that opened the connection (pretty much as lsof does).

Since lsof is open source, I could write the following code to get all the open files for a process:

Bridging-Header:

#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>

(I don't think every include is needed, but at least it compiles for now).

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.")
        }
    }

The code was ported from C to Swift 3. The original C code looks like this:

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

When I run my code, I get the errno 12 (Out of memory). Why?

P.S. I know that the second proc_pidinfo will also fail because a pointer to an array of proc_fdinfo is returned and not a pointer to a single struct, but one step at a time. It's all about the errno 12.


Solution

  • There are two errors. First, it should be

    let size = MemoryLayout<proc_taskallinfo>.size
    

    Second, the proc_pidinfo(pid, PROC_PIDLISTFDS, ...) expects a buffer with room for fileCount structures of type proc_fdinfo, not just a single one:

    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)