]>
Commit | Line | Data |
---|---|---|
2618b3e9 JF |
1 | #include <launch.h> |
2 | #include <notify.h> | |
3 | ||
4 | #include <stdio.h> | |
b9124f59 | 5 | #include <unistd.h> |
2618b3e9 JF |
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 | ||
b9124f59 JF |
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 | ||
2618b3e9 | 124 | int main(int argc, const char *argv[]) { |
2dd5da16 | 125 | _assert(argc == 1, "usage: sbreload"); |
2618b3e9 | 126 | |
2618b3e9 | 127 | CFDictionaryRef plist = CreateMyPropertyListFromFile("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"); |
b9124f59 | 128 | _assert(plist != NULL, "CreateMyPropertyListFromFile() == NULL"); |
2618b3e9 JF |
129 | |
130 | launch_data_t job = CF2launch_data(plist); | |
b9124f59 | 131 | _assert(job != NULL, "CF2launch_data() == NULL"); |
2618b3e9 | 132 | |
b9124f59 JF |
133 | launch_data_t data, request, response; |
134 | ||
135 | data = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL); | |
136 | _assert(data != NULL, "launch_data_dict_lookup(LABEL) == NULL"); | |
137 | const char *label = launch_data_get_string(data); | |
138 | ||
139 | request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
140 | launch_data_dict_insert(request, launch_data_new_string(label), LAUNCH_KEY_GETJOB); | |
2618b3e9 | 141 | |
2618b3e9 | 142 | response = launch_msg(request); |
b9124f59 JF |
143 | _assert(response != NULL, "launch_msg(GetJob) == NULL"); |
144 | launch_data_free(request); | |
2618b3e9 | 145 | |
b9124f59 JF |
146 | pid_t pid; |
147 | ||
148 | if (launch_data_get_type(response) == LAUNCH_DATA_ERRNO) { | |
149 | int error = launch_data_get_errno(response); | |
150 | _assert(error == ESRCH, "GetJob(%s): %s", label, strerror(error)); | |
151 | pid = -1; | |
152 | } else if (launch_data_get_type(response) == LAUNCH_DATA_DICTIONARY) { | |
153 | data = launch_data_dict_lookup(response, LAUNCH_JOBKEY_PID); | |
154 | _assert(data != NULL, "launch_data_dict_lookup(PID) == NULL"); | |
155 | pid = launch_data_get_integer(data); | |
156 | } else _assert(false, "launch_data_get_type() not in (DICTIONARY, ERRNO)"); | |
157 | ||
158 | launch_data_free(response); | |
159 | ||
160 | fprintf(stderr, "notify_post(com.apple.mobile.springboard_teardown)\n"); | |
161 | notify_post("com.apple.mobile.springboard_teardown"); | |
2618b3e9 | 162 | |
b9124f59 JF |
163 | if (pid != -1) { |
164 | fprintf(stderr, "waiting for kill(%u) != 0...\n", pid); | |
165 | while (kill(pid, 0) == 0) | |
166 | stop(); | |
167 | ||
168 | int error = errno; | |
169 | _assert(error == ESRCH, "kill(%u): %s", pid, strerror(error)); | |
2618b3e9 JF |
170 | } |
171 | ||
b9124f59 JF |
172 | request = launch_data_alloc(LAUNCH_DATA_DICTIONARY); |
173 | launch_data_dict_insert(request, job, LAUNCH_KEY_SUBMITJOB); | |
174 | ||
2dd5da16 JF |
175 | for (;;) { |
176 | response = launch_msg(request); | |
177 | _assert(response != NULL, "launch_msg(SubmitJob) == NULL"); | |
b9124f59 | 178 | |
2dd5da16 JF |
179 | _assert(launch_data_get_type(response) == LAUNCH_DATA_ERRNO, "launch_data_get_type() != ERRNO"); |
180 | int error = launch_data_get_errno(response); | |
181 | launch_data_free(response); | |
2618b3e9 | 182 | |
2dd5da16 | 183 | const char *string = strerror(error); |
2618b3e9 | 184 | |
2dd5da16 JF |
185 | if (error == EEXIST) { |
186 | fprintf(stderr, "SubmitJob(%s): %s, retrying...\n", label, string); | |
187 | stop(); | |
188 | } else { | |
189 | _assert(error == 0, "SubmitJob(%s): %s", label, string); | |
190 | break; | |
191 | } | |
2618b3e9 JF |
192 | } |
193 | ||
194 | launch_data_free(request); | |
195 | ||
196 | return 0; | |
197 | } |