1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
{ stdenv, uhubctl, runCommand, writeText, ...}:
let
uhubDaemon = writeText "uhubDaemon.c" ''
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <mach/mach_port.h>
#include <mach/mach_interface.h>
#include <mach/mach_init.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/IOMessage.h>
io_connect_t root_port; // a reference to the Root Power Domain IOService
void MySleepCallBack( void * refCon, io_service_t service, natural_t messageType, void * messageArgument ) {
switch ( messageType ) {
case kIOMessageCanSystemSleep:
IOAllowPowerChange( root_port, (long)messageArgument );
break;
case kIOMessageSystemWillSleep:
system("${uhubctl}/bin/uhubctl -n 0bda -p 2-2 -a off");
IOAllowPowerChange( root_port, (long)messageArgument );
break;
case kIOMessageSystemWillPowerOn:
system("${uhubctl}/bin/uhubctl -n 0bda -p 2-2 -a on");
break;
case kIOMessageSystemHasPoweredOn:
//System has finished waking up...
break;
default:
break;
}
}
int main( int argc, char **argv ) {
// notification port allocated by IORegisterForSystemPower
IONotificationPortRef notifyPortRef;
// notifier object, used to deregister later
io_object_t notifierObject;
// this parameter is passed to the callback
void* refCon;
// register to receive system sleep notifications
root_port = IORegisterForSystemPower( refCon, ¬ifyPortRef, MySleepCallBack, ¬ifierObject );
if ( root_port == 0 ) {
printf("IORegisterForSystemPower failed\n");
return 1;
}
// add the notification port to the application runloop
CFRunLoopAddSource( CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes );
/* Start the run loop to receive sleep notifications. Don't call CFRunLoopRun if this code
is running on the main thread of a Cocoa or Carbon application. Cocoa and Carbon
manage the main thread's run loop for you as part of their event handling
mechanisms.
*/
CFRunLoopRun();
//Not reached, CFRunLoopRun doesn't return in this case.
return (0);
}
'';
buildSymlinks = runCommand "macvim-build-symlinks" {} ''
mkdir -p $out/bin
ln -s /usr/bin/gcc $out/bin
'';
in stdenv.mkDerivation {
name = "uhubDaemon";
src = ./.;
nativeBuildInputs = [ buildSymlinks ];
sandboxProfile = ''
(allow file-read* file-write* process-exec mach-lookup)
; block homebrew dependencies
(deny file-read* file-write* process-exec mach-lookup (subpath "/usr/local") (with no-log))
'';
buildPhase = "gcc -framework IOKit -framework Cocoa -lcurl -o uhubDaemon ${uhubDaemon}";
installPhase = ''
mkdir -p $out/bin
cp uhubDaemon $out/bin/
'';
}