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()