Re: Trouble using DiskArbitration interface

Ronald Oussoren <[email protected]> Wed, 18 Jan 2017 20:46:47 +0100
Newsgroups gmane.comp.python.pyobjc.devel
Message-ID <[email protected]>
> On 2 Jan 2017, at 17:08, Merlijn B.W. Wajer <[email protected]> wrote:
> 
> Hi,
> 
> I'm working on porting some CD archival software from Ubuntu to OS X,
> and I am trying to prevent OS X from mounting CDs, because it interferes
> with the CD ripping process.
> 
> I've found that I can register with 'diskarbitrationd' and register a
> callback when a disk is about to be mounted: using
> DiskArbitration.da.DARegisterDiskMountApprovalCallback
> 
> Using this interface, I've been able to block mount requests
> successfully. However, after some time, usually after blocking a few
> mounts, my simple python program segfaults, and I am pretty sure it has
> something to do with memory management. I've tried to find information
> about this on the official documentation, but that was a bit hard to
> find, apart from "Do not worry about reference counting".
> 
> I am trying to re-create code from here, but in python with pyobjc:
> https://developer.apple.com/library/content/documentation/DriversKernelHardware/Conceptual/DiskArbitrationProgGuide/ArbitrationBasics/ArbitrationBasics.html
> (section "Approving or Refusing a Request")
> 
> 
> Example [1] will always segfault, after (or while) returning from
> allow_mount.
> Example [2] is hacky, and works for a while, and will then segfault, but
> confirms my suspicion that memory management issues are causing these
> problems.
> 
> Specifically, I fear that the dissenter object that I create is somehow
> being freed or corrupted. However, if create it only once for the
> program lifetime, I get similar issues - so it seems like it is simply
> being freed at some point?
> 
> Triggering OS X to mount can be done like so:
> 
> 	diskutil mount /dev/disk1
> 
> if the mount is blocked, it will say:
> 
> 	Volume on disk1 failed to mount; if it has a partitioning scheme, use
> "diskutil mountDisk"
> 	If the volume is damaged, try the "readOnly" option
> 
> And unmounting can be done like so:
> 
> 	diskutil unmount /Volumes/Audio\ CD/
> 
> Any suggestions on how to tackle or debug this problem are most welcome. :-)

Which version of PyObjC are you using? Likewise for the python version.

Ronald


> 
> Regards,
> Merlijn
> 
> 
> 
> Example 1:
> 
> Output:
> 
> $ python osxdiskarbitration-example.py
> OSXDA: start_blocking started
> OSXDA: Session: <DASession 0x7fc9a9fa2ee0 [0x1059e9ed0]>{id = python
> [3595]:7947}
> OSXDA: allow_mount call:  <DADisk 0x7fc9ab800600 [0x1059e9ed0]>{id =
> /dev/disk1} 0
> OSXDA: Blocking mount
> 
> 
> Code:
> 
> from __future__ import print_function
> import objc
> objc.options.verbose = True
> import DiskArbitration as da
> 
> @objc.callbackFor(da.DARegisterDiskMountApprovalCallback)
> def allow_mount(disk, context):
>    print('OSXDA: allow_mount call: ', disk, context)
> 
>    if True:
>        #dissenter = da.DADissenterCreate(da.kCFAllocatorDefault,
>        #                                  da.kDAReturnExclusiveAccess,
> None)
> 
>        # We cannot pass kDAReturnExclusiveAccess initially, for some
> reason, this raises:
>        # ValueError: depythonifying 'int', got 'int' of wrong magnitude
>        # So set it to 42, and change it later
>        dissenter = da.DADissenterCreate(da.kCFAllocatorDefault, 42, None)
>        dissenter["DAStatus"] = da.kDAReturnExclusiveAccess
> 
>        print('OSXDA: Blocking mount')
>        return dissenter # Deny
>    else:
>        print('OSXDA: Allowing mount')
>        return None # Allow
> 
> def start_blocking():
>    print('OSXDA: start_blocking started')
>    session = da.DASessionCreate(da.kCFAllocatorDefault)
> 
>    if not session:
>        print('OSXDA: Failed to create session')
>        exit(1)
> 
>    print('OSXDA: Session:', session)
> 
>    da.DASessionScheduleWithRunLoop(session, da.CFRunLoopGetMain(),
>                                    da.kCFRunLoopCommonModes);
>    #da.DASessionScheduleWithRunLoop(session, da.CFRunLoopGetCurrent(),
>    #                                da.kCFRunLoopDefaultMode);
> 
>    # Register callback
>    da.DARegisterDiskMountApprovalCallback(session, None, allow_mount, None)
> 
>    da.CFRunLoopRun()
> 
>    da.DASessionUnscheduleWithRunLoop(session, da.CFRunLoopGetCurrent(),
> da.kCFRunLoopDefaultMode);
> 
>    print('OSXDA: Done with loop')
> 
>    CFRelease(session)
> 
> if __name__ == '__main__':
>    start_blocking()
> 
> 
> Example 2:
> 
> Output:
> 
> $ python osxdiskarbitration-example-2.py
> OSXDA: start_blocking started
> OSXDA: Session: <DASession 0x7f8e9bf56cf0 [0x1022aced0]>{id = python
> [3644]:7947}
> OSXDA: allow_mount call:  <DADisk 0x7f8e9be73340 [0x1022aced0]>{id =
> /dev/disk1} 0
> OSXDA: Blocking mount
> OSXDA: allow_mount call:  <DADisk 0x7f8e9bd052e0 [0x1022aced0]>{id =
> /dev/disk1} 0
> OSXDA: Blocking mount
> OSXDA: allow_mount call:  <DADisk 0x7f8e9be73340 [0x1022aced0]>{id =
> /dev/disk1} 0
> OSXDA: Blocking mount
> OSXDA: allow_mount call:  <DADisk 0x7f8e9be73340 [0x1022aced0]>{id =
> /dev/disk1} 0
> OSXDA: Blocking mount
> OSXDA: allow_mount call:  <DADisk 0x7f8e9be73b80 [0x1022aced0]>{id =
> /dev/disk1} 0
> OSXDA: Blocking mount
> OSXDA: allow_mount call:  <DADisk 0x7f8e9be75240 [0x1022aced0]>{id =
> /dev/disk1} 0
> Segmentation fault: 11
> 
> Code:
> 
> from __future__ import print_function
> import objc
> objc.options.verbose = True
> import DiskArbitration as da
> 
> memhack = []
> 
> @objc.callbackFor(da.DARegisterDiskMountApprovalCallback)
> def allow_mount(disk, context):
>    print('OSXDA: allow_mount call: ', disk, context)
> 
>    if True:
>        #dissenter = da.DADissenterCreate(da.kCFAllocatorDefault,
>        #                                  da.kDAReturnExclusiveAccess,
> None)
> 
>        # We cannot pass kDAReturnExclusiveAccess initially, for some
> reason, this raises:
>        # ValueError: depythonifying 'int', got 'int' of wrong magnitude
>        # So set it to 42, and change it later
>        dissenter = da.DADissenterCreate(da.kCFAllocatorDefault, 42, None)
>        dissenter["DAStatus"] = da.kDAReturnExclusiveAccess
>        memhack.append(dissenter)
> 
>        print('OSXDA: Blocking mount')
>        return dissenter # Deny
>    else:
>        print('OSXDA: Allowing mount')
>        return None # Allow
> 
> def start_blocking():
>    print('OSXDA: start_blocking started')
>    session = da.DASessionCreate(da.kCFAllocatorDefault)
> 
>    if not session:
>        print('OSXDA: Failed to create session')
>        exit(1)
> 
>    print('OSXDA: Session:', session)
> 
>    da.DASessionScheduleWithRunLoop(session, da.CFRunLoopGetMain(),
>                                    da.kCFRunLoopCommonModes);
>    #da.DASessionScheduleWithRunLoop(session, da.CFRunLoopGetCurrent(),
>    #                                da.kCFRunLoopDefaultMode);
> 
>    # Register callback
>    da.DARegisterDiskMountApprovalCallback(session, None, allow_mount, None)
> 
>    da.CFRunLoopRun()
> 
>    da.DASessionUnscheduleWithRunLoop(session, da.CFRunLoopGetCurrent(),
> da.kCFRunLoopDefaultMode);
> 
>    print('OSXDA: Done with loop')
> 
>    CFRelease(session)
> 
> if __name__ == '__main__':
>    start_blocking()
> 
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most 
> engaging tech sites, SlashDot.org! http://sdm.link/slashdot
> _______________________________________________
> Pyobjc-dev mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/pyobjc-dev


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot