List all processes with arguments in Swift - 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);
}

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

Related

How to get arguments of NSRunningApplication?

How do I get the list of arguments using during launch for a NSRunningApplication, similar to the ones I see when I run ps aux:
let workspace = NSWorkspace.shared
let applications = workspace.runningApplications
for application in applications {
// how do I get arguments that were used during application launch?
}
The "ps" tool uses sysctl() with KERN_PROCARGS2 to get the arguments of a running process. The following is an attempt to translate the code from adv_cmds-153/ps/print.c to Swift. That file also contains a documentation of the memory layout of the raw argument space and explains how to locate the string arguments in that memory.
func processArguments(pid: pid_t) -> [String]? {
// Determine space for arguments:
var name : [CInt] = [ CTL_KERN, KERN_PROCARGS2, pid ]
var length: size_t = 0
if sysctl(&name, CUnsignedInt(name.count), nil, &length, nil, 0) == -1 {
return nil
}
// Get raw arguments:
var buffer = [CChar](repeating: 0, count: length)
if sysctl(&name, CUnsignedInt(name.count), &buffer, &length, nil, 0) == -1 {
return nil
}
// There should be at least the space for the argument count:
var argc : CInt = 0
if length < MemoryLayout.size(ofValue: argc) {
return nil
}
var argv: [String] = []
buffer.withUnsafeBufferPointer { bp in
// Get argc:
memcpy(&argc, bp.baseAddress, MemoryLayout.size(ofValue: argc))
var pos = MemoryLayout.size(ofValue: argc)
// Skip the saved exec_path.
while pos < bp.count && bp[pos] != 0 {
pos += 1
}
if pos == bp.count {
return
}
// Skip trailing '\0' characters.
while pos < bp.count && bp[pos] == 0 {
pos += 1
}
if pos == bp.count {
return
}
// Iterate through the '\0'-terminated strings.
for _ in 0..<argc {
let start = bp.baseAddress! + pos
while pos < bp.count && bp[pos] != 0 {
pos += 1
}
if pos == bp.count {
return
}
argv.append(String(cString: start))
pos += 1
}
}
return argv.count == argc ? argv : nil
}
There is only a simple error handling: if anything goes wrong, the function returns nil.
For an instance of NSRunningApplication you can then call
processArguments(pid: application.processIdentifier)

why cannot read the receipt data for on-device validation

I am using the following code to read the receipt data. I can successfully validate the receipt signature by using OpenSSL static library 1.1.1k
private func readReceipt(_ receiptPKCS7: UnsafeMutablePointer<PKCS7>?) {
// Get a pointer to the start and end of the ASN.1 payload
let receiptSign = receiptPKCS7?.pointee.d.sign
let octets = receiptSign?.pointee.contents.pointee.d.data
var ptr = UnsafePointer(octets?.pointee.data)
let end = ptr!.advanced(by: Int(octets!.pointee.length))
var type: Int32 = 0
var xclass: Int32 = 0
var length: Int = 0
ASN1_get_object(&ptr, &length, &type, &xclass, ptr!.distance(to: end))
guard type == V_ASN1_SET else {
status = .unexpectedASN1Type
return
}
// 1
while ptr! < end {
// 2
ASN1_get_object(&ptr, &length, &type, &xclass, ptr!.distance(to: end))
guard type == V_ASN1_SEQUENCE else {
status = .unexpectedASN1Type
return
}
// 3 type
guard let attributeType = readASN1Integer(ptr: &ptr, maxLength: length) else {
status = .unexpectedASN1Type
return
}
print("shark-IAP, ", attributeType)
// 4 version
guard let _ = readASN1Integer(ptr: &ptr, maxLength: ptr!.distance(to: end)) else {
print("shark-IAP, 3")
status = .unexpectedASN1Type
return
}
// 5 value
ASN1_get_object(&ptr, &length, &type, &xclass, ptr!.distance(to: end))
guard type == V_ASN1_OCTET_STRING else {
print("shark-IAP, 4")
status = .unexpectedASN1Type
return
}
switch attributeType {
case 2: // The bundle identifier
var stringStartPtr = ptr
bundleIdString = readASN1String(ptr: &stringStartPtr, maxLength: length)
bundleIdData = readASN1Data(ptr: ptr!, length: length)
case 3: // Bundle version
var stringStartPtr = ptr
bundleVersionString = readASN1String(ptr: &stringStartPtr, maxLength: length)
case 4: // Opaque value
let dataStartPtr = ptr!
opaqueData = readASN1Data(ptr: dataStartPtr, length: length)
case 5: // Computed GUID (SHA-1 Hash)
let dataStartPtr = ptr!
hashData = readASN1Data(ptr: dataStartPtr, length: length)
case 12: // Receipt Creation Date
var dateStartPtr = ptr
receiptCreationDate = readASN1Date(ptr: &dateStartPtr, maxLength: length)
case 17: // IAP Receipt
var iapStartPtr = ptr
let parsedReceipt = IAPReceipt(with: &iapStartPtr, payloadLength: length)
if let newReceipt = parsedReceipt {
inAppReceipts.append(newReceipt)
}
case 19: // Original App Version
var stringStartPtr = ptr
originalAppVersion = readASN1String(ptr: &stringStartPtr, maxLength: length)
case 21: // Expiration Date
var dateStartPtr = ptr
expirationDate = readASN1Date(ptr: &dateStartPtr, maxLength: length)
default: // Ignore other attributes in receipt
print("Not processing attribute type: \(attributeType)")
}
// Advance pointer to the next item
ptr = ptr!.advanced(by: length)
} // end while
}
func readASN1Integer(ptr: inout UnsafePointer<UInt8>?, maxLength: Int) -> Int? {
var type: Int32 = 0
var xclass: Int32 = 0
var length: Int = 0
ASN1_get_object(&ptr, &length, &type, &xclass, maxLength)
guard type == V_ASN1_INTEGER else {
print("shark-IAP no!", type)
return nil
}
// let integerObject = c2i_ASN1_INTEGER(nil, &ptr, length)
let integerObject = d2i_ASN1_UINTEGER(nil, &ptr, length)
let intValue = ASN1_INTEGER_get(integerObject)
ASN1_INTEGER_free(integerObject)
return intValue
}
I got these print outputs. I suspect the function readASN1Integer is wrong. Maybe c2i_ASN1_INTEGER will be fine but this is deprecated in OpenSSL 1.1*, that d2i_ASN1_UINTEGER is used instead. And d2i_ASN1_UINTEGER needs to pass (identifier + length/octet + content), not just the content. In ASN1_get_object, the pointer has changed position. So d2i_ASN1_UINTEGER reads wrong. The first readASN1Integer causes bias that the second readASN1Integer throws error.
shark-IAP, 0
shark-IAP no! 8
shark-IAP, 3
shark-IAP, bundleVersionString nil
shark-IAP, expirationData nil
shark-IAP, 0
shark-IAP no! 8
shark-IAP, 3
shark-IAP, bundleVersionString nil
shark-IAP, expirationData nil
But I dont' know how to adjust the code to suit d2i_ASN1_UINTEGER. Thank you for your help!
Stackoverflow is a place to suppress devils.
I found the solution. I modified the readASN1Integer to this
func readASN1Integer(ptr: inout UnsafePointer<UInt8>?, maxLength: Int) -> Int? {
var type: Int32 = 0
var xclass: Int32 = 0
var length: Int = 0
let save_ptr = ptr
ASN1_get_object(&ptr, &length, &type, &xclass, maxLength)
guard type == V_ASN1_INTEGER else {
return nil
}
// let integerObject = c2i_ASN1_INTEGER(nil, &ptr, length)
ptr = save_ptr
let integerObject = d2i_ASN1_UINTEGER(nil, &ptr, maxLength)
let intValue = ASN1_INTEGER_get(integerObject)
ASN1_INTEGER_free(integerObject)
return intValue
}
Since the pointer position is changed, need to set it back, that's why save_ptr comes (referenced from c2i_ASN1_INTEGER function in Openssl 1.1.0)
d2i_ASN1_UINTEGER(nil, &ptr, length) is changed to d2i_ASN1_UINTEGER(nil, &ptr, maxLength). For every place, including in readReceipt, length should be maxLength or ptr!.distance(to: end).

Swift “UDP Read” code - unsaferawbufferpointer compile error

I’m sure someone can solve this in seconds but I’m very new to swift, using playgrounds on the iPad. I’m trying to modify some SendUDP code to recieve instead, but I can’t solve the compile error (unsafepointer is not convertible to unsaferawbufferpointer) on the readResult= line. The SEND works fine with very similar code, but I’m really struggling here, way out of my depth...
Here’s the code
func readUDP() {
guard
let addresses =
try ? addressesFor(host: "192.168.4.1", port: 80)
else {
print("host not found")
return
}
if addresses.count != 1 {
print("host ambiguous; using the first one")
}
address = addresses[0]
fd1 = socket(Int32(address.ss_family), SOCK_DGRAM, 0)
guard fd1 >= 0
else {
print("`socket` failed`")
return
}
defer {
let junk = close(fd1)
assert(junk == 0)
}
var message = [UInt8](repeating: 0, count: 1024)
let messageCount = message.count
var readResult = message.withUnsafeBytes {
(messagePtr: UnsafePointer < UInt8 > ) - > Int in
return address.withSockAddr {
(sa, saLen) - > Int in
return recvfrom(fd1, messagePtr, messageCount, 0, sa, & saLen)
}
}
guard readResult >= 0
else {
print("read failed")
return
}
print("success")
}
You can use Swift's implicit bridging to simplify to something like this:
var message = [UInt8](repeating: 0, count: 1024)
let messageCount = message.count
var readResult = address.withSockAddr {
(sa, saLen) - > Int in
return recvfrom(fd1, &message, messageCount, 0, sa, &saLen)
}
guard readResult >= 0
else {
print("read failed")
return
}

How to read values of SparseMatrix_Double in Swift 4?

How do I write a function for printing out the contents of SparseMatrix_Double for Swift 4?
I have the following code so far, however, the output is only correct some of the time.
Sometimes the array is accessing memory that's out of range giving [[1.06540896337e-313, 0.0], [0.0, 3.0]]
I suspect that the way I obtain the number of nonzeros is wrong.
import Accelerate
func toString(_ A: SparseMatrix_Double) throws -> String {
if A.structure.rowCount > 100 || A.structure.columnCount > 100 {
print("Matrix is too big to display")
throw NSError(domain: "Matrix is too big to display", code: -1, userInfo: nil)
}
let rows = Int(A.structure.rowCount)
let columns = Int(A.structure.columnCount)
let nonzeros = A.structure.columnStarts[columns]
print("Row indices")
for i in 0..<nonzeros {
print("\(i): \(A.structure.rowIndices[i])")
}
print("Column starts")
for c in 0...columns {
print("\(c): \(A.structure.columnStarts[c])")
}
var M = Array(repeating: Array(repeating: 0.0, count: columns), count: rows)
var i = 0
var currentColumn: Int = 0
var nextColStarts = A.structure.columnStarts[1]
while currentColumn < (columns - 1) {
if i == nextColStarts {
currentColumn += 1
nextColStarts = A.structure.columnStarts[currentColumn + 1]
}
let rowIndex = Int(A.structure.rowIndices[i])
M[rowIndex][currentColumn] = A.data[i]
print("Setting \(rowIndex),\(currentColumn) [\(i)]")
i += 1
}
return M.description
}
var rows: [Int32] = [1]
var columns: [Int32] = [1]
var values: [Double] = [3.0]
let blockSize: UInt8 = 1
let blockCount = 8
let A = SparseConvertFromCoordinate(
2, 2,
blockCount, blockSize,
SparseAttributes_t(),
&rows, &columns,
&values
)
print(try? toString(A))

What's the best way to cut Swift string into 2-letter-strings?

I need to split a string into 2-letter pieces. Like “friend" -> "fr" "ie" "nd". (Okay, its a step for me to change HEX string to Uint8 Array)
My code is
for i=0; i<chars.count/2; i++ {
let str = input[input.startIndex.advancedBy(i*2)..<input.startIndex.advancedBy(i*2+1)]
bytes.append(UInt8(str,radix: 16)!)
}
But I don't know why I cannot use Range to do this split. And I have no idea what will happen when i*2+1 is bigger than string's length. So what's the best way to cut Swift string into 2-letter-strings?
Your range wasn't working because you need to use ... instead of ..<.
let input = "ff103"
var bytes = [UInt8]()
let strlen = input.characters.count
for i in 0 ..< (strlen + 1)/2 {
let str = input[input.startIndex.advancedBy(i*2)...input.startIndex.advancedBy(min(strlen - 1, i*2+1))]
bytes.append(UInt8(str,radix: 16) ?? 0)
}
print(bytes) // [255, 16, 3]
Here is another take on splitting the string into 2-letter strings. advancedBy() is an expensive O(n) operation, so this version keeps track of start and just marches it ahead by 2 each loop, and end is based on start:
let input = "friends"
var strings = [String]()
let strlen = input.characters.count
var start = input.startIndex
let lastIndex = strlen > 0 ? input.endIndex.predecessor() : input.startIndex
for i in 0 ..< (strlen + 1)/2 {
start = i > 0 ? start.advancedBy(2) : start
let end = start < lastIndex ? start.successor() : start
let str = input[start...end]
strings.append(str)
}
print(strings) // ["fr", "ie", "nd", "s"]
Alternate Answer:
Using ranges is probably overkill. It is easy just to add the characters to an array and make Strings from those:
let input = "friends"
var strings = [String]()
var newchars = [Character]()
for c in input.characters {
newchars.append(c)
if newchars.count == 2 {
strings.append(String(newchars))
newchars = []
}
}
if newchars.count > 0 {
strings.append(String(newchars))
}
print(strings) // ["fr", "ie", "nd", "s"]
And here is the new version for making [UInt8]:
let input = "ff103"
var bytes = [UInt8]()
var newchars = [Character]()
for c in input.characters {
newchars.append(c)
if newchars.count == 2 {
bytes.append(UInt8(String(newchars), radix: 16) ?? 0)
newchars = []
}
}
if newchars.count > 0 {
bytes.append(UInt8(String(newchars), radix: 16) ?? 0)
}
print(bytes) // [255, 16, 3]
Based on #LeoDabus' answer, we can make an extension with a method that will return substrings of any length, and a computed property that returns [UInt8]:
extension String {
func substringsOfLength(length: Int) -> [String] {
if length < 1 { return [] }
var result:[String] = []
let chars = Array(characters)
for index in 0.stride(to: chars.count, by: length) {
result.append(String(chars[index ..< min(index+length, chars.count)]))
}
return result
}
var toUInt8: [UInt8] {
var result:[UInt8] = []
let chars = Array(characters)
for index in 0.stride(to: chars.count, by: 2) {
let str = String(chars[index ..< min(index+2, chars.count)])
result.append(UInt8(str, radix: 16) ?? 0)
}
return result
}
}
let input = "friends"
let str2 = input.substringsOfLength(2) // ["fr", "ie", "nd", "s"]
let str0 = input.substringsOfLength(0) // []
let str3 = input.substringsOfLength(3) // ["fri", "end", "s"]
let bytes = "ff107".toUInt8 // [255, 16, 7]
Another option just for fun:
extension String {
var pairs:[String] {
var result:[String] = []
let chars = Array(characters)
for index in 0.stride(to: chars.count, by: 2) {
result.append(String(chars[index..<min(index+2, chars.count)]))
}
return result
}
}
let input = "friends"
let pairs = input.pairs
print(pairs) // ["fr", "ie", "nd", "s"]