]> git.saurik.com Git - uikittools.git/blob - sbreload.c
20a7da9e6602b6bb76554f0601e9a2314cee5ff5
[uikittools.git] / sbreload.c
1 #include <launch.h>
2 #include <notify.h>
3
4 #include <stdio.h>
5 #include <unistd.h>
6
7 #include <CoreFoundation/CoreFoundation.h>
8
9 launch_data_t
10 CF2launch_data(CFTypeRef cfr);
11
12 void
13 myCFDictionaryApplyFunction(const void *key, const void *value, void *context)
14 {
15 launch_data_t ik, iw, where = context;
16
17 ik = CF2launch_data(key);
18 iw = CF2launch_data(value);
19
20 launch_data_dict_insert(where, iw, launch_data_get_string(ik));
21 launch_data_free(ik);
22 }
23
24 launch_data_t
25 CF2launch_data(CFTypeRef cfr)
26 {
27 launch_data_t r;
28 CFTypeID cft = CFGetTypeID(cfr);
29
30 if (cft == CFStringGetTypeID()) {
31 char buf[4096];
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);
43 if (v) {
44 launch_data_t iv = CF2launch_data(v);
45 launch_data_array_set_index(r, iv, i);
46 }
47 }
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()) {
55 long long n;
56 double d;
57 CFNumberType cfnt = CFNumberGetType(cfr);
58 switch (cfnt) {
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);
71 break;
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);
79 break;
80 default:
81 r = NULL;
82 break;
83 }
84 } else {
85 r = NULL;
86 }
87 return r;
88 }
89
90 CFPropertyListRef
91 CreateMyPropertyListFromFile(const char *posixfile)
92 {
93 CFPropertyListRef propertyList;
94 CFStringRef errorString;
95 CFDataRef resourceData;
96 SInt32 errorCode;
97 CFURLRef fileURL;
98
99 fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false);
100 if (!fileURL) {
101 fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile);
102 }
103 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) {
104 fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode);
105 }
106 propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString);
107 if (!propertyList) {
108 fprintf(stderr, "%s: propertyList is NULL\n", getprogname());
109 }
110
111 return propertyList;
112 }
113
114 #define _assert(test, format, args...) do { \
115 if (test) break; \
116 fprintf(stderr, format "\n", ##args); \
117 return 1; \
118 } while (false)
119
120 void stop() {
121 sleep(1);
122 }
123
124 #define SpringBoard_plist "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
125
126 int main(int argc, const char *argv[]) {
127 _assert(argc == 1, "usage: sbreload");
128
129 CFDictionaryRef plist = CreateMyPropertyListFromFile(SpringBoard_plist);
130 _assert(plist != NULL, "CreateMyPropertyListFromFile() == NULL");
131
132 launch_data_t job = CF2launch_data(plist);
133 _assert(job != NULL, "CF2launch_data() == NULL");
134
135 launch_data_t data, request, response;
136
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);
140
141 request = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
142 launch_data_dict_insert(request, launch_data_new_string(label), LAUNCH_KEY_GETJOB);
143
144 response = launch_msg(request);
145 _assert(response != NULL, "launch_msg(GetJob) == NULL");
146 launch_data_free(request);
147
148 pid_t pid;
149
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));
153 pid = -1;
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)");
159
160 launch_data_free(response);
161
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");
166 } else {
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");
170
171 fprintf(stderr, "launchctl unload SpringBoard.plist\n");
172 system("launchctl unload " SpringBoard_plist);
173 }
174
175 if (pid != -1) {
176 fprintf(stderr, "waiting for kill(%u) != 0...\n", pid);
177 while (kill(pid, 0) == 0)
178 stop();
179
180 int error = errno;
181 _assert(error == ESRCH, "kill(%u): %s", pid, strerror(error));
182 }
183
184 request = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
185 launch_data_dict_insert(request, job, LAUNCH_KEY_SUBMITJOB);
186
187 for (;;) {
188 response = launch_msg(request);
189 _assert(response != NULL, "launch_msg(SubmitJob) == NULL");
190
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);
194
195 const char *string = strerror(error);
196
197 if (error == EEXIST) {
198 fprintf(stderr, "SubmitJob(%s): %s, retrying...\n", label, string);
199 stop();
200 } else {
201 _assert(error == 0, "SubmitJob(%s): %s", label, string);
202 break;
203 }
204 }
205
206 launch_data_free(request);
207
208 return 0;
209 }