1 /* UIKit Tools - command-line utilities for UIKit
2 * Copyright (C) 2008-2012 Jay Freeman (saurik)
5 /* Modified BSD License {{{ */
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
11 * 1. Redistributions of source code must retain the
12 * above copyright notice, this list of conditions
13 * and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the
15 * above copyright notice, this list of conditions
16 * and the following disclaimer in the documentation
17 * and/or other materials provided with the
19 * 3. The name of the author may not be used to endorse
20 * or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
25 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 #include <CoreFoundation/CoreFoundation.h>
49 CF2launch_data(CFTypeRef cfr
);
52 myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
)
54 launch_data_t ik
, iw
, where
= context
;
56 ik
= CF2launch_data(key
);
57 iw
= CF2launch_data(value
);
59 launch_data_dict_insert(where
, iw
, launch_data_get_string(ik
));
64 CF2launch_data(CFTypeRef cfr
)
67 CFTypeID cft
= CFGetTypeID(cfr
);
69 if (cft
== CFStringGetTypeID()) {
71 CFStringGetCString(cfr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
);
72 r
= launch_data_alloc(LAUNCH_DATA_STRING
);
73 launch_data_set_string(r
, buf
);
74 } else if (cft
== CFBooleanGetTypeID()) {
75 r
= launch_data_alloc(LAUNCH_DATA_BOOL
);
76 launch_data_set_bool(r
, CFBooleanGetValue(cfr
));
77 } else if (cft
== CFArrayGetTypeID()) {
78 CFIndex i
, ac
= CFArrayGetCount(cfr
);
79 r
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
80 for (i
= 0; i
< ac
; i
++) {
81 CFTypeRef v
= CFArrayGetValueAtIndex(cfr
, i
);
83 launch_data_t iv
= CF2launch_data(v
);
84 launch_data_array_set_index(r
, iv
, i
);
87 } else if (cft
== CFDictionaryGetTypeID()) {
88 r
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
89 CFDictionaryApplyFunction(cfr
, myCFDictionaryApplyFunction
, r
);
90 } else if (cft
== CFDataGetTypeID()) {
91 r
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
92 launch_data_set_opaque(r
, CFDataGetBytePtr(cfr
), CFDataGetLength(cfr
));
93 } else if (cft
== CFNumberGetTypeID()) {
96 CFNumberType cfnt
= CFNumberGetType(cfr
);
98 case kCFNumberSInt8Type
:
99 case kCFNumberSInt16Type
:
100 case kCFNumberSInt32Type
:
101 case kCFNumberSInt64Type
:
102 case kCFNumberCharType
:
103 case kCFNumberShortType
:
104 case kCFNumberIntType
:
105 case kCFNumberLongType
:
106 case kCFNumberLongLongType
:
107 CFNumberGetValue(cfr
, kCFNumberLongLongType
, &n
);
108 r
= launch_data_alloc(LAUNCH_DATA_INTEGER
);
109 launch_data_set_integer(r
, n
);
111 case kCFNumberFloat32Type
:
112 case kCFNumberFloat64Type
:
113 case kCFNumberFloatType
:
114 case kCFNumberDoubleType
:
115 CFNumberGetValue(cfr
, kCFNumberDoubleType
, &d
);
116 r
= launch_data_alloc(LAUNCH_DATA_REAL
);
117 launch_data_set_real(r
, d
);
130 CreateMyPropertyListFromFile(const char *posixfile
)
132 CFPropertyListRef propertyList
;
133 CFStringRef errorString
;
134 CFDataRef resourceData
;
138 fileURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, (const UInt8
*)posixfile
, strlen(posixfile
), false);
140 fprintf(stderr
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile
);
142 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, fileURL
, &resourceData
, NULL
, NULL
, &errorCode
)) {
143 fprintf(stderr
, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile
, (int)errorCode
);
145 propertyList
= CFPropertyListCreateFromXMLData(kCFAllocatorDefault
, resourceData
, kCFPropertyListMutableContainers
, &errorString
);
147 fprintf(stderr
, "%s: propertyList is NULL\n", getprogname());
153 #define _assert(test, format, args...) do { \
155 fprintf(stderr, format "\n", ##args); \
163 #define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
165 int main(int argc
, const char *argv
[]) {
166 _assert(argc
== 1, "usage: sbreload");
168 CFDictionaryRef plist
= CreateMyPropertyListFromFile(SpringBoard_plist
);
169 _assert(plist
!= NULL
, "CreateMyPropertyListFromFile() == NULL");
171 launch_data_t job
= CF2launch_data(plist
);
172 _assert(job
!= NULL
, "CF2launch_data() == NULL");
174 launch_data_t data
, request
, response
;
176 data
= launch_data_dict_lookup(job
, LAUNCH_JOBKEY_LABEL
);
177 _assert(data
!= NULL
, "launch_data_dict_lookup(LABEL) == NULL");
178 const char *label
= launch_data_get_string(data
);
180 request
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
181 launch_data_dict_insert(request
, launch_data_new_string(label
), LAUNCH_KEY_GETJOB
);
183 response
= launch_msg(request
);
184 _assert(response
!= NULL
, "launch_msg(GetJob) == NULL");
185 launch_data_free(request
);
189 if (launch_data_get_type(response
) == LAUNCH_DATA_ERRNO
) {
190 int error
= launch_data_get_errno(response
);
191 _assert(error
== ESRCH
, "GetJob(%s): %s", label
, strerror(error
));
193 } else if (launch_data_get_type(response
) == LAUNCH_DATA_DICTIONARY
) {
194 data
= launch_data_dict_lookup(response
, LAUNCH_JOBKEY_PID
);
195 _assert(data
!= NULL
, "launch_data_dict_lookup(PID) == NULL");
196 pid
= launch_data_get_integer(data
);
197 } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)");
199 launch_data_free(response
);
201 // 600 is being used to approximate 4.x/5.x boundary
202 if (kCFCoreFoundationVersionNumber
< 600) {
203 fprintf(stderr
, "notify_post(com.apple.mobile.springboard_teardown)\n");
204 notify_post("com.apple.mobile.springboard_teardown");
206 // XXX: this code is preferable to launchctl unoad but it requires libvproc? :(
207 //vproc_err_t *error = _vproc_send_signal_by_label(label, VPROC_MAGIC_UNLOAD_SIGNAL);
208 //_assert(error == NULL, "_vproc_send_signal_by_label(UNLOAD) != NULL");
210 fprintf(stderr
, "launchctl unload SpringBoard.plist\n");
211 system("launchctl unload " SpringBoard_plist
);
215 fprintf(stderr
, "waiting for kill(%u) != 0...\n", pid
);
216 while (kill(pid
, 0) == 0)
220 _assert(error
== ESRCH
, "kill(%u): %s", pid
, strerror(error
));
223 request
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
224 launch_data_dict_insert(request
, job
, LAUNCH_KEY_SUBMITJOB
);
227 response
= launch_msg(request
);
228 _assert(response
!= NULL
, "launch_msg(SubmitJob) == NULL");
230 _assert(launch_data_get_type(response
) == LAUNCH_DATA_ERRNO
, "launch_data_get_type() != ERRNO");
231 int error
= launch_data_get_errno(response
);
232 launch_data_free(response
);
234 const char *string
= strerror(error
);
236 if (error
== EEXIST
) {
237 fprintf(stderr
, "SubmitJob(%s): %s, retrying...\n", label
, string
);
240 _assert(error
== 0, "SubmitJob(%s): %s", label
, string
);
245 launch_data_free(request
);