From 16ba547c702a577f8f26854de947462e57d55cd6 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Thu, 28 Aug 2025 20:00:21 -0400 Subject: [PATCH 01/10] Try things --- x/examples/objc/README.md | 53 +++++++++ x/examples/objc/clangwrap.sh | 14 +++ x/examples/objc/process_info.go | 194 ++++++++++++++++++++++++++++++++ 3 files changed, 261 insertions(+) create mode 100644 x/examples/objc/README.md create mode 100755 x/examples/objc/clangwrap.sh create mode 100644 x/examples/objc/process_info.go diff --git a/x/examples/objc/README.md b/x/examples/objc/README.md new file mode 100644 index 00000000..a3207699 --- /dev/null +++ b/x/examples/objc/README.md @@ -0,0 +1,53 @@ + + + +This works as macOS: + +```console +$ GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x run ./examples/objc +Attempting to get iOS process info using Cgo... + +--- Successfully Retrieved Process Info --- +Process Name: objc +Process ID (PID): 72134 +User Name: +Full User Name: +Globally Unique ID: +OS Version: Version 15.6.1 (Build 24G90) +Hostname: +Is Mac Catalyst App: false +Is iOS App on Mac: false +Physical Memory (B): 17178869184 +System Uptime (s): 198843.16 +Processor Count: 10 +Active Processor Count: 10 +``` + +This seems to properly build for iOS: + +```console +$ CC="$(pwd)/x/examples/objc/clangwrap.sh" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v ./examples/objc +github.com/Jigsaw-Code/outline-sdk/x/examples/objc +# github.com/Jigsaw-Code/outline-sdk/x/examples/objc +examples/objc/process_info.go:74:47: error: 'userName' is unavailable: not available on iOS + 74 | p_info->userName = safe_strdup([[info userName] UTF8String]); + | ^ +/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.4.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSProcessInfo.h:192:38: note: property 'userName' is declared unavailable here + 192 | @property (readonly, copy) NSString *userName API_AVAILABLE(macosx(10.12)) API_UNAVAILABLE(ios, watchos, tvos); + | ^ +/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.4.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSProcessInfo.h:192:38: note: 'userName' has been explicitly marked unavailable here +examples/objc/process_info.go:75:51: error: 'fullUserName' is unavailable: not available on iOS + 75 | p_info->fullUserName = safe_strdup([[info fullUserName] UTF8String]); + | ^ +/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.4.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSProcessInfo.h:193:38: note: property 'fullUserName' is declared unavailable here + 193 | @property (readonly, copy) NSString *fullUserName API_AVAILABLE(macosx(10.12)) API_UNAVAILABLE(ios, watchos, tvos); + | ^ +/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.4.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSProcessInfo.h:193:38: note: 'fullUserName' has been explicitly marked unavailable here +2 errors generated. +``` + +Alternatively: + +``` +CC="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -isysroot \"$(xcrun --sdk "iphoneos" --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v ./examples/objc +``` diff --git a/x/examples/objc/clangwrap.sh b/x/examples/objc/clangwrap.sh new file mode 100755 index 00000000..a3bfb162 --- /dev/null +++ b/x/examples/objc/clangwrap.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +# From https://medium.com/using-go-in-mobile-apps/using-go-in-mobile-apps-part-2-building-an-ios-app-with-go-build-eb1fc3b56c99 + +# This uses the latest available iOS SDK, which is recommended. +# To select a specific SDK, run ‘xcodebuild -showsdks’ +# to see the available SDKs and replace iphoneos with one of them. +SDK=iphoneos +SDK_PATH="$(xcrun --sdk "${SDK}" --show-sdk-path)" +# export IPHONEOS_DEPLOYMENT_TARGET=7.0 +# cmd/cgo doesn’t support llvm-gcc-4.2, so we have to use clang. +CLANG="$(xcrun --sdk iphoneos --find clang)" +# -arch armv7 -isysroot "$SDK_PATH" "$@" +exec "$CLANG" -isysroot "$SDK_PATH" "$@" \ No newline at end of file diff --git a/x/examples/objc/process_info.go b/x/examples/objc/process_info.go new file mode 100644 index 00000000..70473dca --- /dev/null +++ b/x/examples/objc/process_info.go @@ -0,0 +1,194 @@ +// Copyright 2025 The Outline Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +/* +// These Cgo directives are essential for compiling on an Apple platform. +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation + +#import +#include // For malloc, free, strdup + +// A C struct to hold all the process information we want to retrieve. +// This allows us to get all the data in a single Cgo call. +typedef struct { + char* processName; + int processIdentifier; + char* globallyUniqueString; + char* operatingSystemVersionString; + char* hostName; + unsigned long long physicalMemory; + double systemUptime; + int processorCount; + int activeProcessorCount; + // New fields from your request + int isMacCatalystApp; + int isiOSAppOnMac; + char* userName; + char* fullUserName; +} ProcessInfo_t; + +// A helper function to safely duplicate a C string that might be NULL. +// strdup(NULL) is undefined behavior, so this prevents crashes. +static char* safe_strdup(const char* s) { + if (s == NULL) { + // Return a dynamically allocated empty string. + return strdup(""); + } + return strdup(s); +} + + +// This C function (using Objective-C) populates and returns a struct +// containing a wide range of process information. +static ProcessInfo_t* get_all_process_info() { + // Autorelease pool is good practice for managing memory in Objective-C code + // called from other languages. + @autoreleasepool { + NSProcessInfo *info = [NSProcessInfo processInfo]; + + // Allocate memory for our C struct. + ProcessInfo_t *p_info = (ProcessInfo_t*)malloc(sizeof(ProcessInfo_t)); + if (p_info == NULL) { + return NULL; // Failed to allocate memory + } + + // Use safe_strdup to create heap-allocated C string copies that Go can safely manage and free. + p_info->processName = safe_strdup([[info processName] UTF8String]); + p_info->globallyUniqueString = safe_strdup([[info globallyUniqueString] UTF8String]); + p_info->operatingSystemVersionString = safe_strdup([[info operatingSystemVersionString] UTF8String]); + p_info->hostName = safe_strdup([[info hostName] UTF8String]); + // p_info->userName = safe_strdup([[info userName] UTF8String]); + // p_info->fullUserName = safe_strdup([[info fullUserName] UTF8String]); + + // Populate numeric fields directly. + p_info->processIdentifier = [info processIdentifier]; + p_info->physicalMemory = [info physicalMemory]; + p_info->systemUptime = [info systemUptime]; + p_info->processorCount = (int)[info processorCount]; + p_info->activeProcessorCount = (int)[info activeProcessorCount]; + + // Populate boolean flags (as integers), checking for API availability. + if (@available(macOS 10.15, iOS 13.0, *)) { + p_info->isMacCatalystApp = [info isMacCatalystApp] ? 1 : 0; + } else { + p_info->isMacCatalystApp = 0; // Default to false on older systems. + } + + if (@available(macOS 11.0, iOS 14.0, *)) { + p_info->isiOSAppOnMac = [info isiOSAppOnMac] ? 1 : 0; + } else { + p_info->isiOSAppOnMac = 0; // Default to false on older systems. + } + + return p_info; + } +} +*/ +import "C" +import ( + "fmt" + "log" + "unsafe" +) + +// A Go struct that mirrors the C struct, providing an idiomatic way +// to work with the process information in Go. +type ProcessInfo struct { + ProcessName string + ProcessIdentifier int + GloballyUniqueString string + OperatingSystemVersionString string + HostName string + PhysicalMemoryBytes uint64 + SystemUptimeSeconds float64 + ProcessorCount int + ActiveProcessorCount int + IsMacCatalystApp bool + IsIOSAppOnMac bool + UserName string + FullUserName string +} + +// getProcessInfo is a Go wrapper function that calls the underlying C function +// and converts the C struct into a Go struct. +func getProcessInfo() (*ProcessInfo, error) { + // Call the C function to get the populated struct. + cInfo := C.get_all_process_info() + + // Check if the C function returned NULL, which indicates an error. + if cInfo == nil { + return nil, fmt.Errorf("failed to get process info from NSProcessInfo") + } + + // The memory for the C struct and its string members was allocated in C. + // We must free all of it to prevent memory leaks. The defer statements + // ensure C.free is called for each allocated piece of memory right + // before the function returns. + defer C.free(unsafe.Pointer(cInfo.processName)) + defer C.free(unsafe.Pointer(cInfo.globallyUniqueString)) + defer C.free(unsafe.Pointer(cInfo.operatingSystemVersionString)) + defer C.free(unsafe.Pointer(cInfo.hostName)) + defer C.free(unsafe.Pointer(cInfo.userName)) + defer C.free(unsafe.Pointer(cInfo.fullUserName)) + defer C.free(unsafe.Pointer(cInfo)) + + // Create a Go struct and copy the data from the C struct, converting types as needed. + goInfo := &ProcessInfo{ + ProcessName: C.GoString(cInfo.processName), + ProcessIdentifier: int(cInfo.processIdentifier), + GloballyUniqueString: C.GoString(cInfo.globallyUniqueString), + OperatingSystemVersionString: C.GoString(cInfo.operatingSystemVersionString), + HostName: C.GoString(cInfo.hostName), + PhysicalMemoryBytes: uint64(cInfo.physicalMemory), + SystemUptimeSeconds: float64(cInfo.systemUptime), + ProcessorCount: int(cInfo.processorCount), + ActiveProcessorCount: int(cInfo.activeProcessorCount), + IsMacCatalystApp: cInfo.isMacCatalystApp != 0, + IsIOSAppOnMac: cInfo.isiOSAppOnMac != 0, + UserName: C.GoString(cInfo.userName), + FullUserName: C.GoString(cInfo.fullUserName), + } + + return goInfo, nil +} + +func main() { + fmt.Println("Attempting to get iOS process info using Cgo...") + + // Call our Go wrapper function. + info, err := getProcessInfo() + if err != nil { + log.Fatalf("Error: %v", err) + } + + // Print all the retrieved information in a formatted way. + fmt.Printf("\n--- Successfully Retrieved Process Info ---\n") + fmt.Printf("Process Name: %s\n", info.ProcessName) + fmt.Printf("Process ID (PID): %d\n", info.ProcessIdentifier) + fmt.Printf("User Name: %s\n", info.UserName) + fmt.Printf("Full User Name: %s\n", info.FullUserName) + fmt.Printf("Globally Unique ID: %s\n", info.GloballyUniqueString) + fmt.Printf("OS Version: %s\n", info.OperatingSystemVersionString) + fmt.Printf("Hostname: %s\n", info.HostName) + fmt.Printf("Is Mac Catalyst App: %t\n", info.IsMacCatalystApp) + fmt.Printf("Is iOS App on Mac: %t\n", info.IsIOSAppOnMac) + fmt.Printf("Physical Memory (B): %d\n", info.PhysicalMemoryBytes) + fmt.Printf("System Uptime (s): %.2f\n", info.SystemUptimeSeconds) + fmt.Printf("Processor Count: %d\n", info.ProcessorCount) + fmt.Printf("Active Processor Count: %d\n", info.ActiveProcessorCount) + fmt.Println("-------------------------------------------") +} From 3310b66b8e7df018c02a8fca62aef2149ddd4d31 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 13:55:40 -0400 Subject: [PATCH 02/10] Update without sh script --- x/examples/objc/README.md | 12 +++++++----- x/examples/objc/clangwrap.sh | 14 -------------- 2 files changed, 7 insertions(+), 19 deletions(-) delete mode 100755 x/examples/objc/clangwrap.sh diff --git a/x/examples/objc/README.md b/x/examples/objc/README.md index a3207699..e10e9a13 100644 --- a/x/examples/objc/README.md +++ b/x/examples/objc/README.md @@ -26,7 +26,8 @@ Active Processor Count: 10 This seems to properly build for iOS: ```console -$ CC="$(pwd)/x/examples/objc/clangwrap.sh" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v ./examples/objc +% CC="$(xcrun --sdk iphoneos --find cc) -isysroot \"$(xcrun --sdk iphoneos --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build  -v ./examples/objc + github.com/Jigsaw-Code/outline-sdk/x/examples/objc # github.com/Jigsaw-Code/outline-sdk/x/examples/objc examples/objc/process_info.go:74:47: error: 'userName' is unavailable: not available on iOS @@ -46,8 +47,9 @@ examples/objc/process_info.go:75:51: error: 'fullUserName' is unavailable: not a 2 errors generated. ``` -Alternatively: -``` -CC="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -isysroot \"$(xcrun --sdk "iphoneos" --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v ./examples/objc -``` +For the simulator: + +```console +% CC="$(xcrun --sdk iphonesimulator --find cc) -isysroot \"$(xcrun --sdk iphonesimulator --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v ./examples/objc +``` \ No newline at end of file diff --git a/x/examples/objc/clangwrap.sh b/x/examples/objc/clangwrap.sh deleted file mode 100755 index a3bfb162..00000000 --- a/x/examples/objc/clangwrap.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -# From https://medium.com/using-go-in-mobile-apps/using-go-in-mobile-apps-part-2-building-an-ios-app-with-go-build-eb1fc3b56c99 - -# This uses the latest available iOS SDK, which is recommended. -# To select a specific SDK, run ‘xcodebuild -showsdks’ -# to see the available SDKs and replace iphoneos with one of them. -SDK=iphoneos -SDK_PATH="$(xcrun --sdk "${SDK}" --show-sdk-path)" -# export IPHONEOS_DEPLOYMENT_TARGET=7.0 -# cmd/cgo doesn’t support llvm-gcc-4.2, so we have to use clang. -CLANG="$(xcrun --sdk iphoneos --find clang)" -# -arch armv7 -isysroot "$SDK_PATH" "$@" -exec "$CLANG" -isysroot "$SDK_PATH" "$@" \ No newline at end of file From c13c3e1d1244e12b1ed8eb12fbfd9557544e79c7 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 14:03:54 -0400 Subject: [PATCH 03/10] Install and run --- x/examples/objc/ProcessInfo.app/Info.plist | 26 ++++++++++++++++++++++ x/examples/objc/README.md | 12 ++++++++++ 2 files changed, 38 insertions(+) create mode 100644 x/examples/objc/ProcessInfo.app/Info.plist diff --git a/x/examples/objc/ProcessInfo.app/Info.plist b/x/examples/objc/ProcessInfo.app/Info.plist new file mode 100644 index 00000000..600904f9 --- /dev/null +++ b/x/examples/objc/ProcessInfo.app/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleExecutable + objc + + CFBundleIdentifier + org.getoutline.test + + CFBundleName + ProcessInfo + + CFBundlePackageType + APPL + + CFBundleShortVersionString + 1.0 + + CFBundleVersion + 1 + + LSRequiresIPhoneOS + + + diff --git a/x/examples/objc/README.md b/x/examples/objc/README.md index e10e9a13..d18b4d4f 100644 --- a/x/examples/objc/README.md +++ b/x/examples/objc/README.md @@ -52,4 +52,16 @@ For the simulator: ```console % CC="$(xcrun --sdk iphonesimulator --find cc) -isysroot \"$(xcrun --sdk iphonesimulator --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v ./examples/objc +``` + +Building the app: + +``` +% CC="$(xcrun --sdk iphonesimulator --find cc) -isysroot \"$(xcrun --sdk iphonesimulator --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v -o examples/objc/ProcessInfo.app ./examples/objc + +% xcrun simctl boot 529EC4D4-FFC6-4249-A829-0D8181639E9D + +% xcrun simctl install booted ./x/examples/objc/ProcessInfo.app + +% xcrun simctl launch --console booted org.getoutline.test ``` \ No newline at end of file From a91a2e4e69b00e7b571803d8ed510d0b8588b00d Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 14:11:11 -0400 Subject: [PATCH 04/10] Yes! --- x/examples/objc/README.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/x/examples/objc/README.md b/x/examples/objc/README.md index d18b4d4f..9084d3a9 100644 --- a/x/examples/objc/README.md +++ b/x/examples/objc/README.md @@ -54,7 +54,7 @@ For the simulator: % CC="$(xcrun --sdk iphonesimulator --find cc) -isysroot \"$(xcrun --sdk iphonesimulator --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v ./examples/objc ``` -Building the app: +If you build it for the iOS Simulator, you can run on the iOS simulator. It correctly returns the iOS version on the simulator (18.4), though notice that "Is iOS App on Mac" is false, because it's not "on Mac". ``` % CC="$(xcrun --sdk iphonesimulator --find cc) -isysroot \"$(xcrun --sdk iphonesimulator --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v -o examples/objc/ProcessInfo.app ./examples/objc @@ -64,4 +64,22 @@ Building the app: % xcrun simctl install booted ./x/examples/objc/ProcessInfo.app % xcrun simctl launch --console booted org.getoutline.test -``` \ No newline at end of file +org.getoutline.test: 41369 +Attempting to get iOS process info using Cgo... + +--- Successfully Retrieved Process Info --- +Process Name: objc +Process ID (PID): 41369 +User Name: +Full User Name: +Globally Unique ID: 8BA56801-5364-4D9C-A4F6-17F9681C1FF2-41369-00000900466BD6C9 +OS Version: Version 18.4 (Build 22E238) +Hostname: fortuna-macbookpro2.roam.internal +Is Mac Catalyst App: false +Is iOS App on Mac: false +Physical Memory (B): 17179869184 +System Uptime (s): 412366.44 +Processor Count: 10 +Active Processor Count: 10 +------------------------------------------- +``` From cfadcb51733d87685ec095efecf984cda0feae3d Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 14:17:44 -0400 Subject: [PATCH 05/10] Rename to main --- x/examples/objc/ProcessInfo.app/Info.plist | 2 +- x/examples/objc/README.md | 12 ++++++------ x/examples/objc/{process_info.go => main.go} | 0 3 files changed, 7 insertions(+), 7 deletions(-) rename x/examples/objc/{process_info.go => main.go} (100%) diff --git a/x/examples/objc/ProcessInfo.app/Info.plist b/x/examples/objc/ProcessInfo.app/Info.plist index 600904f9..2b10ed6d 100644 --- a/x/examples/objc/ProcessInfo.app/Info.plist +++ b/x/examples/objc/ProcessInfo.app/Info.plist @@ -3,7 +3,7 @@ CFBundleExecutable - objc + main CFBundleIdentifier org.getoutline.test diff --git a/x/examples/objc/README.md b/x/examples/objc/README.md index 9084d3a9..cc498d1e 100644 --- a/x/examples/objc/README.md +++ b/x/examples/objc/README.md @@ -57,28 +57,28 @@ For the simulator: If you build it for the iOS Simulator, you can run on the iOS simulator. It correctly returns the iOS version on the simulator (18.4), though notice that "Is iOS App on Mac" is false, because it's not "on Mac". ``` -% CC="$(xcrun --sdk iphonesimulator --find cc) -isysroot \"$(xcrun --sdk iphonesimulator --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v -o examples/objc/ProcessInfo.app ./examples/objc +% CC="$(xcrun --sdk iphonesimulator --find cc) -isysroot \"$(xcrun --sdk iphonesimulator --show-sdk-path)\"" GOOS=ios GOARCH=arm64 CGO_ENABLED=1 go -C x build -v -o examples/objc/ProcessInfo.app ./examples/objc/main.go % xcrun simctl boot 529EC4D4-FFC6-4249-A829-0D8181639E9D % xcrun simctl install booted ./x/examples/objc/ProcessInfo.app % xcrun simctl launch --console booted org.getoutline.test -org.getoutline.test: 41369 +org.getoutline.test: 43075 Attempting to get iOS process info using Cgo... --- Successfully Retrieved Process Info --- -Process Name: objc -Process ID (PID): 41369 +Process Name: main +Process ID (PID): 43075 User Name: Full User Name: -Globally Unique ID: 8BA56801-5364-4D9C-A4F6-17F9681C1FF2-41369-00000900466BD6C9 +Globally Unique ID: 5A277847-FAB1-491C-930F-AEBFB8BC145C-43075-00000903D8910887 OS Version: Version 18.4 (Build 22E238) Hostname: fortuna-macbookpro2.roam.internal Is Mac Catalyst App: false Is iOS App on Mac: false Physical Memory (B): 17179869184 -System Uptime (s): 412366.44 +System Uptime (s): 413005.42 Processor Count: 10 Active Processor Count: 10 ------------------------------------------- diff --git a/x/examples/objc/process_info.go b/x/examples/objc/main.go similarity index 100% rename from x/examples/objc/process_info.go rename to x/examples/objc/main.go From 47e76cbc6711d3d724a31d4344dfb3ad230c9506 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 14:19:45 -0400 Subject: [PATCH 06/10] Add build constraint --- x/examples/objc/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/examples/objc/main.go b/x/examples/objc/main.go index 70473dca..7baa90b1 100644 --- a/x/examples/objc/main.go +++ b/x/examples/objc/main.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build darwin + package main /* From 9ad4966d738de0d48ea8371f466a15fbf61c5c47 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 14:57:45 -0400 Subject: [PATCH 07/10] Add IsIOS --- x/examples/objc/main.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/x/examples/objc/main.go b/x/examples/objc/main.go index 7baa90b1..8e9d937e 100644 --- a/x/examples/objc/main.go +++ b/x/examples/objc/main.go @@ -39,6 +39,7 @@ typedef struct { // New fields from your request int isMacCatalystApp; int isiOSAppOnMac; + int isIOS; char* userName; char* fullUserName; } ProcessInfo_t; @@ -90,6 +91,12 @@ static ProcessInfo_t* get_all_process_info() { p_info->isMacCatalystApp = 0; // Default to false on older systems. } + #if TARGET_OS_IOS + p_info->isIOS = 1; + #else + p_info->isIOS = 0; + #endif + if (@available(macOS 11.0, iOS 14.0, *)) { p_info->isiOSAppOnMac = [info isiOSAppOnMac] ? 1 : 0; } else { @@ -121,6 +128,7 @@ type ProcessInfo struct { ActiveProcessorCount int IsMacCatalystApp bool IsIOSAppOnMac bool + IsIOS bool UserName string FullUserName string } @@ -161,6 +169,7 @@ func getProcessInfo() (*ProcessInfo, error) { ActiveProcessorCount: int(cInfo.activeProcessorCount), IsMacCatalystApp: cInfo.isMacCatalystApp != 0, IsIOSAppOnMac: cInfo.isiOSAppOnMac != 0, + IsIOS: cInfo.isIOS != 0, UserName: C.GoString(cInfo.userName), FullUserName: C.GoString(cInfo.fullUserName), } @@ -188,6 +197,7 @@ func main() { fmt.Printf("Hostname: %s\n", info.HostName) fmt.Printf("Is Mac Catalyst App: %t\n", info.IsMacCatalystApp) fmt.Printf("Is iOS App on Mac: %t\n", info.IsIOSAppOnMac) + fmt.Printf("Is iOS: %t\n", info.IsIOS) fmt.Printf("Physical Memory (B): %d\n", info.PhysicalMemoryBytes) fmt.Printf("System Uptime (s): %.2f\n", info.SystemUptimeSeconds) fmt.Printf("Processor Count: %d\n", info.ProcessorCount) From c42b3bdb7f49c99e8b105200a4c66d1ae6913224 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 15:08:26 -0400 Subject: [PATCH 08/10] IF --- x/examples/objc/main.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/x/examples/objc/main.go b/x/examples/objc/main.go index 8e9d937e..df218290 100644 --- a/x/examples/objc/main.go +++ b/x/examples/objc/main.go @@ -74,8 +74,17 @@ static ProcessInfo_t* get_all_process_info() { p_info->globallyUniqueString = safe_strdup([[info globallyUniqueString] UTF8String]); p_info->operatingSystemVersionString = safe_strdup([[info operatingSystemVersionString] UTF8String]); p_info->hostName = safe_strdup([[info hostName] UTF8String]); - // p_info->userName = safe_strdup([[info userName] UTF8String]); - // p_info->fullUserName = safe_strdup([[info fullUserName] UTF8String]); + + #if TARGET_OS_OSX + // NSUserName and NSFullUserName are only available on macOS. + // We use the modern, non-deprecated functions here. + p_info->userName = safe_strdup([NSUserName() UTF8String]); + p_info->fullUserName = safe_strdup([NSFullUserName() UTF8String]); + #else + // On other platforms (like iOS), provide empty strings to avoid crashes. + p_info->userName = safe_strdup(NULL); + p_info->fullUserName = safe_strdup(NULL); + #endif // Populate numeric fields directly. p_info->processIdentifier = [info processIdentifier]; From f1589b6ee0f6db9a01f6d74a24762d85c6e775d9 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 15:34:09 -0400 Subject: [PATCH 09/10] More info --- x/examples/objc/main.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/x/examples/objc/main.go b/x/examples/objc/main.go index df218290..b602dffd 100644 --- a/x/examples/objc/main.go +++ b/x/examples/objc/main.go @@ -120,7 +120,11 @@ import "C" import ( "fmt" "log" + "log/slog" + "os" "unsafe" + + "golang.org/x/sys/unix" ) // A Go struct that mirrors the C struct, providing an idiomatic way @@ -186,6 +190,18 @@ func getProcessInfo() (*ProcessInfo, error) { return goInfo, nil } +// CstrToString converts a null-terminated []int8 byte slice to a string. +func CstrToString(arr []byte) string { + buf := make([]byte, 0, len(arr)) + for _, v := range arr { + if v == 0x00 { + break + } + buf = append(buf, byte(v)) + } + return string(buf) +} + func main() { fmt.Println("Attempting to get iOS process info using Cgo...") @@ -195,15 +211,27 @@ func main() { log.Fatalf("Error: %v", err) } + osHostname, err := os.Hostname() + if err != nil { + osHostname = err.Error() + } + + uts := new(unix.Utsname) + err = unix.Uname(uts) + if err != nil { + slog.Error("uname failed", "error", err) + } // Print all the retrieved information in a formatted way. fmt.Printf("\n--- Successfully Retrieved Process Info ---\n") fmt.Printf("Process Name: %s\n", info.ProcessName) fmt.Printf("Process ID (PID): %d\n", info.ProcessIdentifier) + fmt.Printf("os.Getpid(): %d\n", os.Getpid()) fmt.Printf("User Name: %s\n", info.UserName) fmt.Printf("Full User Name: %s\n", info.FullUserName) fmt.Printf("Globally Unique ID: %s\n", info.GloballyUniqueString) fmt.Printf("OS Version: %s\n", info.OperatingSystemVersionString) fmt.Printf("Hostname: %s\n", info.HostName) + fmt.Printf("os.Hostname(): %s\n", osHostname) fmt.Printf("Is Mac Catalyst App: %t\n", info.IsMacCatalystApp) fmt.Printf("Is iOS App on Mac: %t\n", info.IsIOSAppOnMac) fmt.Printf("Is iOS: %t\n", info.IsIOS) @@ -211,5 +239,11 @@ func main() { fmt.Printf("System Uptime (s): %.2f\n", info.SystemUptimeSeconds) fmt.Printf("Processor Count: %d\n", info.ProcessorCount) fmt.Printf("Active Processor Count: %d\n", info.ActiveProcessorCount) + fmt.Printf("uname:\n") + fmt.Printf(" Sysname: %s\n", CstrToString(uts.Sysname[:])) + fmt.Printf(" Nodename: %s\n", CstrToString(uts.Nodename[:])) + fmt.Printf(" Release: %s\n", CstrToString(uts.Release[:])) + fmt.Printf(" Version: %s\n", CstrToString(uts.Version[:])) + fmt.Printf(" Machine: %s\n", CstrToString(uts.Machine[:])) fmt.Println("-------------------------------------------") } From c2872b877bec68dd83db6434bd915b00110fbf02 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 2 Sep 2025 15:37:00 -0400 Subject: [PATCH 10/10] Add info --- x/examples/objc/main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/x/examples/objc/main.go b/x/examples/objc/main.go index b602dffd..f42900ee 100644 --- a/x/examples/objc/main.go +++ b/x/examples/objc/main.go @@ -225,13 +225,11 @@ func main() { fmt.Printf("\n--- Successfully Retrieved Process Info ---\n") fmt.Printf("Process Name: %s\n", info.ProcessName) fmt.Printf("Process ID (PID): %d\n", info.ProcessIdentifier) - fmt.Printf("os.Getpid(): %d\n", os.Getpid()) fmt.Printf("User Name: %s\n", info.UserName) fmt.Printf("Full User Name: %s\n", info.FullUserName) fmt.Printf("Globally Unique ID: %s\n", info.GloballyUniqueString) fmt.Printf("OS Version: %s\n", info.OperatingSystemVersionString) fmt.Printf("Hostname: %s\n", info.HostName) - fmt.Printf("os.Hostname(): %s\n", osHostname) fmt.Printf("Is Mac Catalyst App: %t\n", info.IsMacCatalystApp) fmt.Printf("Is iOS App on Mac: %t\n", info.IsIOSAppOnMac) fmt.Printf("Is iOS: %t\n", info.IsIOS) @@ -239,7 +237,10 @@ func main() { fmt.Printf("System Uptime (s): %.2f\n", info.SystemUptimeSeconds) fmt.Printf("Processor Count: %d\n", info.ProcessorCount) fmt.Printf("Active Processor Count: %d\n", info.ActiveProcessorCount) - fmt.Printf("uname:\n") + fmt.Printf("os.Args: %s\n", os.Args) + fmt.Printf("os.Getpid(): %d\n", os.Getpid()) + fmt.Printf("os.Hostname(): %s\n", osHostname) + fmt.Printf("unix.Uname:\n") fmt.Printf(" Sysname: %s\n", CstrToString(uts.Sysname[:])) fmt.Printf(" Nodename: %s\n", CstrToString(uts.Nodename[:])) fmt.Printf(" Release: %s\n", CstrToString(uts.Release[:]))