Search code examples
swiftsysctl

List all processes with arguments in Swift


I'm trying to convert some piece of code to Swift that will list all running processes. But since it requires calling some C specific APIs I'm a bit struggling. Can someone tell me here what am I doing here incorrectly? print statement at the end is outputting incorrect values. I assume it should be process name. Also line info = malloc(length) gives me the creeps. How should I properly allocate it?

var maxArgumentsSize: Int = 0
if maxArgumentsSize == 0 {
    var size: size_t = MemoryLayout<Int>.size
    var mib: [Int32] = [CTL_KERN, KERN_ARGMAX]
    let a = sysctl(&mib, 2, &maxArgumentsSize, &size, nil, 0)
    if a == -1 {
        maxArgumentsSize = 4096;
    }
}

var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_ALL]
var info: UnsafeMutableRawPointer? = nil
var length: size_t = 0
var count: Int = 0

if sysctl(&mib, 3, nil, &length, nil, 0) < 0 {
    exit(EXIT_FAILURE)
}

info = malloc(length)

if sysctl(&mib, 3, info, &length, nil, 0) < 0 {
    free(info)
    exit(EXIT_FAILURE)
}

count = length / MemoryLayout<kinfo_proc>.size
for index in 0...count {
    let info = info?.assumingMemoryBound(to: kinfo_proc.self)
    let pid: pid_t = info![index].kp_proc.p_pid
    let buffer = UnsafeMutablePointer<CChar>.allocate(capacity: maxArgumentsSize)
    var mib: [Int32] = [CTL_KERN, KERN_PROCARGS2, pid]
    if sysctl(&mib, 3, buffer, &maxArgumentsSize, nil, 0) == 0 {
        let str = String(cString: buffer, encoding: .utf8)
        print(str)
    }
    free(buffer);
}

Solution

  • Basically I've changed my initial code to this and calling @MartinR solution (https://stackoverflow.com/a/72445381/1187415) at the end. Of course it's not complete and pasted from my code directly but it's working.

    // Get all processess information:
    var name: [CInt] = [CTL_KERN, KERN_PROC, KERN_PROC_ALL]
    var length: size_t = 0
    if sysctl(&name, CUnsignedInt(name.count), nil, &length, nil, 0) < 0 {
        return
    }
    var infoPtr = UnsafeMutableRawPointer.allocate(
        byteCount: length,
        alignment: MemoryLayout<kinfo_proc>.alignment
    )
    if sysctl(&name, CUnsignedInt(name.count), infoPtr, &length, nil, 0) < 0 {
        infoPtr.deallocate()
        return
    }
    let count = length / MemoryLayout<kinfo_proc>.size
    for index in 0...count {
        let info = infoPtr.assumingMemoryBound(to: kinfo_proc.self)
        let pid: pid_t = info[index].kp_proc.p_pid
        let arguments = self.processArguments(pid: pid)
    }
    infoPtr.deallocate()