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