Skip to content

Commit

Permalink
refactor: iokit to ioregistry
Browse files Browse the repository at this point in the history
  • Loading branch information
doronz88 committed Feb 17, 2022
1 parent 80de260 commit 12ee0bf
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 121 deletions.
4 changes: 2 additions & 2 deletions src/rpcclient/rpcclient/darwin/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from rpcclient.darwin import objective_c_class
from rpcclient.darwin.consts import kCFNumberSInt64Type, kCFNumberDoubleType
from rpcclient.darwin.fs import DarwinFs
from rpcclient.darwin.iokit import IOKit
from rpcclient.darwin.ioregistry import IORegistry
from rpcclient.darwin.media import DarwinMedia
from rpcclient.darwin.network import DarwinNetwork
from rpcclient.darwin.objective_c_symbol import ObjectiveCSymbol
Expand Down Expand Up @@ -57,7 +57,7 @@ def __init__(self, sock, sysname: str, hostname: str, port: int = None):
self.processes = DarwinProcesses(self)
self.media = DarwinMedia(self)
self.network = DarwinNetwork(self)
self.iokit = IOKit(self)
self.ioregistry = IORegistry(self)

@property
def modules(self) -> typing.List[str]:
Expand Down
14 changes: 13 additions & 1 deletion src/rpcclient/rpcclient/darwin/consts.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
kCFAllocatorDefault = 0
MACH_PORT_NULL = 0
AVAudioSessionCategoryOptionDefaultToSpeaker = 0x8

# Types from MacTypes.h

# Basic C types
Expand All @@ -19,4 +23,12 @@
kCFNumberCFIndexType = 14
kCFNumberMaxType = 14

AVAudioSessionCategoryOptionDefaultToSpeaker = 0x8
# Types from IOKitKeys.h

# registry plane names
kIOServicePlane = 'IOService'
kIOPowerPlane = 'IOPower'
kIODeviceTreePlane = 'IODeviceTree'
kIOAudioPlane = 'IOAudio'
kIOFireWirePlane = 'IOFireWire'
kIOUSBPlane = 'IOUSB'
118 changes: 0 additions & 118 deletions src/rpcclient/rpcclient/darwin/iokit.py

This file was deleted.

172 changes: 172 additions & 0 deletions src/rpcclient/rpcclient/darwin/ioregistry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
from typing import Mapping

from rpcclient.darwin.consts import MACH_PORT_NULL, kCFAllocatorDefault, kIOServicePlane
from rpcclient.darwin.structs import mach_port_t, io_name_t, io_object_t
from rpcclient.exceptions import RpcClientException, BadReturnValueError
from rpcclient.allocated import Allocated


class IOServiceIter(Allocated):
def __init__(self, client, service):
super().__init__()
self._client = client
self._service = service

def __iter__(self):
with self._client.safe_malloc(io_object_t.sizeof()) as p_child_iter:
if self._client.symbols.IORegistryEntryGetChildIterator(self._service, kIOServicePlane, p_child_iter):
raise BadReturnValueError('IORegistryEntryGetChildIterator failed')
child_iter = p_child_iter[0]

while True:
child = self._client.symbols.IOIteratorNext(child_iter)
if not child:
break
s = IOService(self._client, child)
yield s

self.deallocate()

def _deallocate(self):
self._client.symbols.IOObjectRelease(self._service)


class IOService(Allocated):
""" representation of a remote IOService """

def __init__(self, client, service):
super().__init__()
self._client = client
self._service = service

@property
def name(self) -> str:
with self._client.safe_malloc(io_name_t.sizeof()) as name:
if self._client.symbols.IORegistryEntryGetName(self._service, name):
raise BadReturnValueError('IORegistryEntryGetName failed')
return name.peek_str()

@property
def properties(self) -> Mapping:
with self._client.safe_malloc(8) as p_properties:
if self._client.symbols.IORegistryEntryCreateCFProperties(self._service, p_properties,
kCFAllocatorDefault, 0):
raise BadReturnValueError('IORegistryEntryCreateCFProperties failed')
return p_properties[0].py

def iter(self) -> IOServiceIter:
return IOServiceIter(self._client, self._service)

def set(self, properties: Mapping):
self._client.symbols.IORegistryEntrySetCFProperties(self._service, self._client.cf(properties))

def get(self, key: str):
return self._client.symbols.IORegistryEntryCreateCFProperty(self._service, self._client.cf(key), 0, 0).py

def _deallocate(self):
self._client.symbols.IOObjectRelease(self._service)

def __repr__(self):
return f'<IOService NAME:{self.name}>'


class BacklightControlService(IOService):
@property
def display_parameters(self) -> Mapping:
return self.get('IODisplayParameters')

@property
def brightness(self) -> int:
return self.display_parameters['brightness']['value']

@brightness.setter
def brightness(self, value: int):
self.set({'EnableBacklight': bool(value)})
self.set({'brightness': value})


class PowerSourceService(IOService):
@property
def battery_voltage(self) -> int:
return self.get('AppleRawBatteryVoltage')

@property
def charging(self) -> bool:
return self.get('IsCharging')

@charging.setter
def charging(self, value: bool):
self.set({'IsCharging': value, 'ExternalConnected': value})

@property
def external_connected(self) -> bool:
return self.get('ExternalConnected')

@external_connected.setter
def external_connected(self, value: bool):
self.set({'ExternalConnected': value})

@property
def current_capacity(self) -> int:
return self.get('CurrentCapacity')

@current_capacity.setter
def current_capacity(self, value: int):
self.set({'CurrentCapacity': value})

@property
def at_warn_level(self) -> bool:
return self.get('AtWarnLevel')

@at_warn_level.setter
def at_warn_level(self, value: bool):
self.set({'AtWarnLevel': value})

@property
def time_remaining(self) -> int:
return self.get('TimeRemaining')

@property
def temperature(self) -> int:
return self.get('Temperature')

@temperature.setter
def temperature(self, value: int):
self.set({'Temperature': value})


class IORegistry:
"""
IORegistry utils
For more information please read:
https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/TheRegistry/TheRegistry.html
"""

def __init__(self, client):
"""
:param rpcclient.darwin.client.DarwinClient client:
"""
self._client = client

@property
def backlight_control(self) -> BacklightControlService:
service = self._client.symbols.IOServiceGetMatchingService(
0, self._client.cf({'IOPropertyMatch': {'backlight-control': True}}))
if not service:
raise RpcClientException('IOServiceGetMatchingService failed')
return BacklightControlService(self._client, service)

@property
def power_source(self) -> PowerSourceService:
service = self._client.symbols.IOServiceGetMatchingService(
0, self._client.symbols.IOServiceMatching('IOPMPowerSource'))
if not service:
raise RpcClientException('IOServiceGetMatchingService failed')
return PowerSourceService(self._client, service)

@property
def root(self) -> IOService:
with self._client.safe_malloc(mach_port_t.sizeof()) as p_master_port:
self._client.symbols.IOMasterPort(MACH_PORT_NULL, p_master_port)
return IOService(self._client, self._client.symbols.IORegistryGetRootEntry(p_master_port[0]))
3 changes: 3 additions & 0 deletions src/rpcclient/rpcclient/darwin/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
blksize_t = Int32ul
ino64_t = Int64ul
fsid_t = Array(2, Int32sl)
mach_port_t = Int64ul
io_name_t = PaddedString(1024, 'utf8')
io_object_t = Int64ul

timespec = Struct(
'tv_sec' / long,
Expand Down

0 comments on commit 12ee0bf

Please sign in to comment.