Home > Mobile >  Getting ioctl numbers in Swift
Getting ioctl numbers in Swift

Time:11-15

what I'm trying to achieve here is getting the ioctl number for ejecting a disk, which I already do in my Bridging Header:

#define DKIOCEJECT  _IO('d', 21)

NSUInteger IOEJECT = DKIOCEJECT;

...and that indeed does work for creating an ioctl request, what I'm trying to do is just that but in Swift rather than having to use a Bridging Header

In C, I'd usually put something like this to get an ioctl number:

#define DKIOCEJECT _IO('d', 21)

The above would usually return an ioctl number, How can I do something similar but in Swift?


Here are all the preprocessor macros:

#define _IO(g, n)        _IOC(IOC_VOID, (g), (n), 0)

#define _IOC(inout, group, num, len) \  (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))

#define IOCPARM_MASK    0x1fff          /* parameter length, at most 13 bits */

define IOC_VOID        (__uint32_t)0x20000000

CodePudding user response:

Given that the _IO macro resolves to a single integer constant, we can follow the preprocessor's logic to reimplement it:

#define DKIOCEJECT                     _IO('d', 21)
#define _IO(g, n)                      _IOC(IOC_VOID, (g), (n), 0)
#define _IOC(inout, group, num, len)   (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
#define IOC_VOID                       (unsigned long)0x20000000
#define IOCPARM_MASK                   0x1fff

Therefore....

DKIOCEJECT  == _IO(g: 'd', n: 21)
            == _IOC(IOC_VOID, ('d'), (21), 0)
            == (IOC_VOID | ((0 & IOCPARM_MASK) << 16) | (('d') << 8) | (21))
            == ( 0x20000000 | (0 << 16) | (('d') << 8) | (21) )
            == ( 0x20000000 | 0         | (0x64 << 8)  | 21   )
            == ( 0x20000000             | 0x6400       | 0x15 )
            == 0x20006415

// For reference:
'd'         == 0x64 // asciitable.com
21          == 0x15

In Swift as a constant from a literal:

enum MyIoctrlNumbers {
    static let DKIOCEJECT: UInt = 0x20006415
}

Swift doesn't support C -style constexpr-expressions, but if you're okay with a runtime-generated static value, then try this:

import Foundation

func getIoctrlNumber( group: Character, n: UInt ) -> UInt {

    let IOC_VOID: UInt = 0x20000000;
    let g       : UInt = UInt( UInt( group.asciiValue! ) << 8 );

    return IOC_VOID | g | n;
}

let asInt = getIoctrlNumber( group: "d", n: 21 );
let asDec = String( asInt, radix: 10 );
let asHex = String( asInt, radix: 16 );
print( "DKIOCEJECT == "     asDec );
print( "DKIOCEJECT == 0x"   asHex );

Gives me this output:

Swift version 5.5.1 (swift-5.5.1-RELEASE)                                                   02:11:39 4s
Target: x86_64-unknown-linux-gnu

DKIOCEJECT == 536896533
DKIOCEJECT == 0x20006415

Apparently Swift does let you populate an enum's values with runtime-init static values (not just consts/literals!), so you could have it like so:

enum MyIoctrlNumbers {

    static let DKIOCEJECT: UInt = getIoctrlNumber( group: "d", n: 21 );
    static let ANOTHER   : Uint = getIoctrlNumber( group: "e", n: 22 );
}

and this works fine:

print( "DKIOCEJECT == "     String( MyIoctrlNumbers.DKIOCEJECT, radix: 10 ));
print( "DKIOCEJECT == 0x"   String( MyIoctrlNumbers.DKIOCEJECT, radix: 16 ) );

Gives me this output:

Swift version 5.5.1 (swift-5.5.1-RELEASE)                                                   02:13:31 6s
Target: x86_64-unknown-linux-gnu


DKIOCEJECT == 536896533
DKIOCEJECT == 0x20006415
  • Related