7 #include <CoreFoundation/CoreFoundation.h>
10 CF2launch_data(CFTypeRef cfr
);
13 myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
)
15 launch_data_t ik
, iw
, where
= context
;
17 ik
= CF2launch_data(key
);
18 iw
= CF2launch_data(value
);
20 launch_data_dict_insert(where
, iw
, launch_data_get_string(ik
));
25 CF2launch_data(CFTypeRef cfr
)
28 CFTypeID cft
= CFGetTypeID(cfr
);
30 if (cft
== CFStringGetTypeID()) {
32 CFStringGetCString(cfr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
);
33 r
= launch_data_alloc(LAUNCH_DATA_STRING
);
34 launch_data_set_string(r
, buf
);
35 } else if (cft
== CFBooleanGetTypeID()) {
36 r
= launch_data_alloc(LAUNCH_DATA_BOOL
);
37 launch_data_set_bool(r
, CFBooleanGetValue(cfr
));
38 } else if (cft
== CFArrayGetTypeID()) {
39 CFIndex i
, ac
= CFArrayGetCount(cfr
);
40 r
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
41 for (i
= 0; i
< ac
; i
++) {
42 CFTypeRef v
= CFArrayGetValueAtIndex(cfr
, i
);
44 launch_data_t iv
= CF2launch_data(v
);
45 launch_data_array_set_index(r
, iv
, i
);
48 } else if (cft
== CFDictionaryGetTypeID()) {
49 r
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
50 CFDictionaryApplyFunction(cfr
, myCFDictionaryApplyFunction
, r
);
51 } else if (cft
== CFDataGetTypeID()) {
52 r
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
53 launch_data_set_opaque(r
, CFDataGetBytePtr(cfr
), CFDataGetLength(cfr
));
54 } else if (cft
== CFNumberGetTypeID()) {
57 CFNumberType cfnt
= CFNumberGetType(cfr
);
59 case kCFNumberSInt8Type
:
60 case kCFNumberSInt16Type
:
61 case kCFNumberSInt32Type
:
62 case kCFNumberSInt64Type
:
63 case kCFNumberCharType
:
64 case kCFNumberShortType
:
65 case kCFNumberIntType
:
66 case kCFNumberLongType
:
67 case kCFNumberLongLongType
:
68 CFNumberGetValue(cfr
, kCFNumberLongLongType
, &n
);
69 r
= launch_data_alloc(LAUNCH_DATA_INTEGER
);
70 launch_data_set_integer(r
, n
);
72 case kCFNumberFloat32Type
:
73 case kCFNumberFloat64Type
:
74 case kCFNumberFloatType
:
75 case kCFNumberDoubleType
:
76 CFNumberGetValue(cfr
, kCFNumberDoubleType
, &d
);
77 r
= launch_data_alloc(LAUNCH_DATA_REAL
);
78 launch_data_set_real(r
, d
);
91 CreateMyPropertyListFromFile(const char *posixfile
)
93 CFPropertyListRef propertyList
;
94 CFStringRef errorString
;
95 CFDataRef resourceData
;
99 fileURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, (const UInt8
*)posixfile
, strlen(posixfile
), false);
101 fprintf(stderr
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile
);
103 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, fileURL
, &resourceData
, NULL
, NULL
, &errorCode
)) {
104 fprintf(stderr
, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile
, (int)errorCode
);
106 propertyList
= CFPropertyListCreateFromXMLData(kCFAllocatorDefault
, resourceData
, kCFPropertyListMutableContainers
, &errorString
);
108 fprintf(stderr
, "%s: propertyList is NULL\n", getprogname());
114 #define _assert(test, format, args...) do { \
116 fprintf(stderr, format "\n", ##args); \
124 #define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
126 int main(int argc
, const char *argv
[]) {
127 _assert(argc
== 1, "usage: sbreload");
129 CFDictionaryRef plist
= CreateMyPropertyListFromFile(SpringBoard_plist
);
130 _assert(plist
!= NULL
, "CreateMyPropertyListFromFile() == NULL");
132 launch_data_t job
= CF2launch_data(plist
);
133 _assert(job
!= NULL
, "CF2launch_data() == NULL");
135 launch_data_t data
, request
, response
;
137 data
= launch_data_dict_lookup(job
, LAUNCH_JOBKEY_LABEL
);
138 _assert(data
!= NULL
, "launch_data_dict_lookup(LABEL) == NULL");
139 const char *label
= launch_data_get_string(data
);
141 request
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
142 launch_data_dict_insert(request
, launch_data_new_string(label
), LAUNCH_KEY_GETJOB
);
144 response
= launch_msg(request
);
145 _assert(response
!= NULL
, "launch_msg(GetJob) == NULL");
146 launch_data_free(request
);
150 if (launch_data_get_type(response
) == LAUNCH_DATA_ERRNO
) {
151 int error
= launch_data_get_errno(response
);
152 _assert(error
== ESRCH
, "GetJob(%s): %s", label
, strerror(error
));
154 } else if (launch_data_get_type(response
) == LAUNCH_DATA_DICTIONARY
) {
155 data
= launch_data_dict_lookup(response
, LAUNCH_JOBKEY_PID
);
156 _assert(data
!= NULL
, "launch_data_dict_lookup(PID) == NULL");
157 pid
= launch_data_get_integer(data
);
158 } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)");
160 launch_data_free(response
);
162 // 600 is being used to approximate 4.x/5.x boundary
163 if (kCFCoreFoundationVersionNumber
< 600) {
164 fprintf(stderr
, "notify_post(com.apple.mobile.springboard_teardown)\n");
165 notify_post("com.apple.mobile.springboard_teardown");
167 // XXX: this code is preferable to launchctl unoad but it requires libvproc? :(
168 //vproc_err_t *error = _vproc_send_signal_by_label(label, VPROC_MAGIC_UNLOAD_SIGNAL);
169 //_assert(error == NULL, "_vproc_send_signal_by_label(UNLOAD) != NULL");
171 fprintf(stderr
, "launchctl unload SpringBoard.plist\n");
172 system("launchctl unload " SpringBoard_plist
);
176 fprintf(stderr
, "waiting for kill(%u) != 0...\n", pid
);
177 while (kill(pid
, 0) == 0)
181 _assert(error
== ESRCH
, "kill(%u): %s", pid
, strerror(error
));
184 request
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
185 launch_data_dict_insert(request
, job
, LAUNCH_KEY_SUBMITJOB
);
188 response
= launch_msg(request
);
189 _assert(response
!= NULL
, "launch_msg(SubmitJob) == NULL");
191 _assert(launch_data_get_type(response
) == LAUNCH_DATA_ERRNO
, "launch_data_get_type() != ERRNO");
192 int error
= launch_data_get_errno(response
);
193 launch_data_free(response
);
195 const char *string
= strerror(error
);
197 if (error
== EEXIST
) {
198 fprintf(stderr
, "SubmitJob(%s): %s, retrying...\n", label
, string
);
201 _assert(error
== 0, "SubmitJob(%s): %s", label
, string
);
206 launch_data_free(request
);