]>
Commit | Line | Data |
---|---|---|
34d340d7 | 1 | /* |
8459d725 | 2 | * Copyright (c) 2006-2007, 2010 Apple Inc. All rights reserved. |
34d340d7 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | #include <stdbool.h> | |
24 | #include <stdlib.h> | |
25 | #include <stdio.h> | |
26 | #include <dirent.h> | |
27 | #include <errno.h> | |
28 | #include <fcntl.h> | |
29 | #include <fts.h> | |
30 | #include <pthread.h> | |
31 | #include <pwd.h> | |
32 | #include <unistd.h> | |
8459d725 | 33 | #include <sys/kauth.h> |
34d340d7 A |
34 | #include <sys/stat.h> |
35 | #include <sys/sysctl.h> | |
36 | #include <sys/time.h> | |
37 | ||
38 | #include <mach/mach.h> | |
39 | #include <mach/mach_error.h> | |
40 | #include <servers/bootstrap.h> | |
41 | ||
42 | #include <bsm/libbsm.h> | |
43 | ||
44 | #include <asl.h> | |
45 | #include <membership.h> | |
46 | #include <launch.h> | |
47 | #include <dirhelper_priv.h> | |
48 | ||
8459d725 | 49 | #include "dirhelper.h" |
aaff5f01 | 50 | #include "dirhelperServer.h" |
8459d725 A |
51 | /* |
52 | * Uncomment the next line to define BOOTDEBUG, which will write timing | |
53 | * info for clean_directories() to a file, /Debug. | |
54 | */ | |
55 | //#define BOOTDEBUG | |
56 | #ifdef BOOTDEBUG | |
57 | #include <mach/mach_time.h> | |
58 | #endif //BOOTDEBUG | |
34d340d7 A |
59 | |
60 | // globals for idle exit | |
61 | struct idle_globals { | |
62 | mach_port_t mp; | |
63 | long timeout; | |
64 | struct timeval lastmsg; | |
65 | }; | |
66 | ||
67 | struct idle_globals idle_globals; | |
68 | ||
8459d725 A |
69 | // argument structure for clean_thread |
70 | struct clean_args { | |
71 | const char** dirs; | |
72 | int machineBoot; | |
73 | }; | |
74 | ||
34d340d7 | 75 | void* idle_thread(void* param __attribute__((unused))); |
fc6d9e4b | 76 | void* clean_thread(void *); |
34d340d7 | 77 | |
8459d725 A |
78 | int file_check(const char* path, int mode, int uid, int gid, uid_t* owner, gid_t* group); |
79 | #define is_file(x) file_check((x), S_IFREG, -1, -1, NULL, NULL) | |
80 | #define is_directory(x) file_check((x), S_IFDIR, -1, -1, NULL, NULL) | |
81 | #define is_directory_get_owner_group(x,o,g) file_check((x), S_IFDIR, -1, -1, (o), (g)) | |
82 | #define is_root_wheel_directory(x) file_check((x), S_IFDIR, 0, 0, NULL, NULL) | |
34d340d7 A |
83 | |
84 | int is_safeboot(void); | |
85 | ||
86 | void clean_files_older_than(const char* path, time_t when); | |
ef8ad44b | 87 | void clean_directories(const char* names[], int); |
34d340d7 A |
88 | |
89 | kern_return_t | |
90 | do___dirhelper_create_user_local( | |
91 | mach_port_t server_port __attribute__((unused)), | |
92 | audit_token_t au_tok) | |
93 | { | |
94 | int res = 0; | |
95 | uid_t euid; | |
96 | gid_t gid = 0; | |
97 | struct passwd* pwd = NULL; | |
98 | ||
99 | gettimeofday(&idle_globals.lastmsg, NULL); | |
100 | ||
101 | audit_token_to_au32(au_tok, | |
102 | NULL, // audit uid | |
103 | &euid, // euid | |
104 | NULL, // egid | |
105 | NULL, // ruid | |
106 | NULL, // rgid | |
107 | NULL, // remote_pid | |
108 | NULL, // asid | |
109 | NULL); // aud_tid_t | |
110 | ||
111 | // Look-up the primary gid of the user. We'll use this for chown(2) | |
112 | // so that the created directory is owned by a group that the user | |
113 | // belongs to, avoiding warnings if files are moved outside this dir. | |
114 | pwd = getpwuid(euid); | |
115 | if (pwd) gid = pwd->pw_gid; | |
116 | ||
117 | do { // begin block | |
118 | char path[PATH_MAX]; | |
119 | char *next; | |
120 | ||
121 | if (__user_local_dirname(euid, DIRHELPER_USER_LOCAL, path, sizeof(path)) == NULL) { | |
122 | asl_log(NULL, NULL, ASL_LEVEL_ERR, | |
123 | "__user_local_dirname: %s", strerror(errno)); | |
124 | break; | |
125 | } | |
8459d725 A |
126 | |
127 | // All dirhelper directories are now at the same level, so | |
128 | // we need to remove the DIRHELPER_TOP_STR suffix to get the | |
129 | // parent directory. | |
130 | path[strlen(path) - (sizeof(DIRHELPER_TOP_STR) - 1)] = 0; | |
34d340d7 A |
131 | |
132 | // | |
133 | // 1. Starting with VAR_FOLDERS_PATH, make each subdirectory | |
134 | // in path, ignoring failure if it already exists. | |
135 | // 2. Change ownership of directory to the user. | |
136 | // | |
137 | next = path + strlen(VAR_FOLDERS_PATH); | |
138 | while ((next = strchr(next, '/')) != NULL) { | |
139 | *next = 0; // temporarily truncate | |
140 | res = mkdir(path, 0755); | |
141 | if (res != 0 && errno != EEXIST) { | |
142 | asl_log(NULL, NULL, ASL_LEVEL_ERR, | |
143 | "mkdir(%s): %s", path, strerror(errno)); | |
144 | break; | |
145 | } | |
146 | *next++ = '/'; // restore the slash and increment | |
147 | } | |
148 | if(next || res) // an error occurred | |
149 | break; | |
150 | res = chown(path, euid, gid); | |
151 | if (res != 0) { | |
152 | asl_log(NULL, NULL, ASL_LEVEL_ERR, | |
153 | "chown(%s): %s", path, strerror(errno)); | |
154 | } | |
155 | } while(0); // end block | |
156 | return KERN_SUCCESS; | |
157 | } | |
158 | ||
159 | kern_return_t | |
160 | do___dirhelper_idle_exit( | |
161 | mach_port_t server_port __attribute__((unused)), | |
162 | audit_token_t au_tok __attribute__((unused))) { | |
163 | ||
164 | struct timeval now; | |
165 | gettimeofday(&now, NULL); | |
166 | long delta = now.tv_sec - idle_globals.lastmsg.tv_sec; | |
167 | if (delta >= idle_globals.timeout) { | |
168 | asl_log(NULL, NULL, ASL_LEVEL_DEBUG, | |
169 | "idle exit after %ld seconds", delta); | |
170 | exit(EXIT_SUCCESS); | |
171 | } | |
172 | ||
173 | return KERN_SUCCESS; | |
174 | } | |
175 | ||
176 | void* | |
177 | idle_thread(void* param __attribute__((unused))) { | |
178 | for(;;) { | |
179 | struct timeval now; | |
180 | gettimeofday(&now, NULL); | |
181 | long delta = (now.tv_sec - idle_globals.lastmsg.tv_sec); | |
182 | if (delta < idle_globals.timeout) { | |
183 | // sleep for remainder of timeout | |
fc6d9e4b | 184 | sleep((int)(idle_globals.timeout - delta)); |
34d340d7 A |
185 | } else { |
186 | // timeout has elapsed, attempt to idle exit | |
187 | __dirhelper_idle_exit(idle_globals.mp); | |
188 | } | |
189 | } | |
190 | return NULL; | |
191 | } | |
192 | ||
8459d725 | 193 | // If when == 0, all files are removed. Otherwise, only regular files that were both created _and_ last modified before `when`. |
34d340d7 A |
194 | void |
195 | clean_files_older_than(const char* path, time_t when) { | |
196 | FTS* fts; | |
197 | ||
198 | char* path_argv[] = { (char*)path, NULL }; | |
199 | fts = fts_open(path_argv, FTS_PHYSICAL | FTS_XDEV, NULL); | |
200 | if (fts) { | |
201 | FTSENT* ent; | |
ef8ad44b | 202 | asl_log(NULL, NULL, ASL_LEVEL_INFO, "Cleaning " VAR_FOLDERS_PATH "%s", path); |
34d340d7 A |
203 | while ((ent = fts_read(fts))) { |
204 | switch(ent->fts_info) { | |
205 | case FTS_F: | |
206 | case FTS_DEFAULT: | |
34d340d7 | 207 | if (when == 0) { |
ef8ad44b A |
208 | #if DEBUG |
209 | asl_log(NULL, NULL, ASL_LEVEL_ALERT, "unlink(" VAR_FOLDERS_PATH "%s)", ent->fts_path); | |
210 | #endif | |
34d340d7 | 211 | (void)unlink(ent->fts_path); |
8459d725 | 212 | } else if (S_ISREG(ent->fts_statp->st_mode) && (ent->fts_statp->st_birthtime < when) && (ent->fts_statp->st_atime < when)) { |
34d340d7 A |
213 | int fd = open(ent->fts_path, O_RDONLY | O_NONBLOCK); |
214 | if (fd != -1) { | |
8459d725 A |
215 | // Obtain an exclusive lock so |
216 | // that we can avoid a race with other processes | |
217 | // attempting to open or modify the file. | |
34d340d7 A |
218 | int res = flock(fd, LOCK_EX | LOCK_NB); |
219 | if (res == 0) { | |
220 | struct stat sb; | |
221 | res = fstat(fd, &sb); | |
8459d725 | 222 | if ((res == 0) && (sb.st_birthtime < when) && (sb.st_atime < when)) { |
ef8ad44b A |
223 | #if DEBUG |
224 | asl_log(NULL, NULL, ASL_LEVEL_ALERT, "unlink(" VAR_FOLDERS_PATH "%s)", ent->fts_path); | |
225 | #endif | |
34d340d7 A |
226 | (void)unlink(ent->fts_path); |
227 | } | |
228 | (void)flock(fd, LOCK_UN); | |
229 | } | |
230 | close(fd); | |
231 | } | |
232 | } | |
233 | break; | |
234 | ||
235 | case FTS_SL: | |
236 | case FTS_SLNONE: | |
237 | if (when == 0) { | |
ef8ad44b A |
238 | #if DEBUG |
239 | asl_log(NULL, NULL, ASL_LEVEL_ALERT, "unlink(" VAR_FOLDERS_PATH "%s)", ent->fts_path); | |
240 | #endif | |
34d340d7 A |
241 | (void)unlink(ent->fts_path); |
242 | } | |
243 | break; | |
244 | ||
245 | case FTS_DP: | |
246 | if (when == 0) { | |
ef8ad44b A |
247 | #if DEBUG |
248 | asl_log(NULL, NULL, ASL_LEVEL_ALERT, "rmdir(" VAR_FOLDERS_PATH "%s)", ent->fts_path); | |
249 | #endif | |
34d340d7 A |
250 | (void)rmdir(ent->fts_path); |
251 | } | |
252 | break; | |
253 | ||
254 | case FTS_ERR: | |
255 | case FTS_NS: | |
ef8ad44b | 256 | asl_log(NULL, NULL, ASL_LEVEL_ERR, VAR_FOLDERS_PATH "%s: %s", ent->fts_path, strerror(ent->fts_errno)); |
34d340d7 A |
257 | break; |
258 | ||
259 | default: | |
260 | break; | |
261 | } | |
262 | } | |
263 | fts_close(fts); | |
264 | } else { | |
ef8ad44b | 265 | asl_log(NULL, NULL, ASL_LEVEL_ERR, VAR_FOLDERS_PATH "%s: %s", path, strerror(errno)); |
34d340d7 A |
266 | } |
267 | } | |
268 | ||
269 | int | |
8459d725 | 270 | file_check(const char* path, int mode, int uid, int gid, uid_t* owner, gid_t* group) { |
34d340d7 A |
271 | int check = 1; |
272 | struct stat sb; | |
273 | if (lstat(path, &sb) == 0) { | |
274 | check = check && ((sb.st_mode & S_IFMT) == mode); | |
275 | check = check && ((sb.st_uid == (uid_t)uid) || uid == -1); | |
276 | check = check && ((sb.st_gid == (gid_t)gid) || gid == -1); | |
8459d725 A |
277 | if (check) { |
278 | if (owner) *owner = sb.st_uid; | |
279 | if (group) *group = sb.st_gid; | |
280 | } | |
34d340d7 A |
281 | } else { |
282 | if (errno != ENOENT) { | |
ef8ad44b | 283 | /* This will print a shorter path after chroot() */ |
34d340d7 A |
284 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", path, strerror(errno)); |
285 | } | |
286 | check = 0; | |
287 | } | |
288 | return check; | |
289 | } | |
290 | ||
291 | int | |
292 | is_safeboot(void) { | |
293 | uint32_t sb = 0; | |
294 | size_t sbsz = sizeof(sb); | |
295 | ||
296 | if (sysctlbyname("kern.safeboot", &sb, &sbsz, NULL, 0) != 0) { | |
297 | return 0; | |
298 | } else { | |
299 | return (int)sb; | |
300 | } | |
301 | } | |
302 | ||
8459d725 A |
303 | void * |
304 | clean_thread(void *a) { | |
305 | struct clean_args* args = (struct clean_args*)a; | |
34d340d7 A |
306 | DIR* d; |
307 | time_t when = 0; | |
ef8ad44b | 308 | int i; |
34d340d7 | 309 | |
8459d725 | 310 | if (!args->machineBoot) { |
34d340d7 A |
311 | struct timeval now; |
312 | long days = 3; | |
313 | const char* str = getenv("CLEAN_FILES_OLDER_THAN_DAYS"); | |
314 | if (str) { | |
315 | days = strtol(str, NULL, 0); | |
316 | } | |
317 | (void)gettimeofday(&now, NULL); | |
8459d725 A |
318 | for (i = 0; args->dirs[i]; i++) |
319 | asl_log(NULL, NULL, ASL_LEVEL_INFO, "Cleaning %s older than %ld days", args->dirs[i], days); | |
34d340d7 A |
320 | |
321 | when = now.tv_sec - (days * 60 * 60 * 24); | |
322 | } | |
323 | ||
324 | // Look up the boot time | |
325 | struct timespec boottime; | |
326 | size_t len = sizeof(boottime); | |
327 | if (sysctlbyname("kern.boottime", &boottime, &len, NULL, 0) == -1) { | |
328 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", "sysctl kern.boottime", strerror(errno)); | |
8459d725 | 329 | return NULL; |
34d340d7 A |
330 | } |
331 | ||
332 | if (!is_root_wheel_directory(VAR_FOLDERS_PATH)) { | |
333 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", VAR_FOLDERS_PATH, "invalid ownership"); | |
8459d725 | 334 | return NULL; |
34d340d7 | 335 | } |
ef8ad44b A |
336 | |
337 | if (chroot(VAR_FOLDERS_PATH)) { | |
338 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "chroot(%s) failed: %s", | |
339 | VAR_FOLDERS_PATH, strerror(errno)); | |
340 | } | |
8459d725 | 341 | chdir("/"); |
ef8ad44b | 342 | if ((d = opendir("/"))) { |
34d340d7 A |
343 | struct dirent* e; |
344 | char path[PATH_MAX]; | |
345 | ||
346 | // /var/folders/* | |
347 | while ((e = readdir(d))) { | |
348 | if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; | |
349 | ||
ef8ad44b | 350 | snprintf(path, sizeof(path), "%s%s", "/", e->d_name); |
34d340d7 A |
351 | if (is_root_wheel_directory(path)) { |
352 | DIR* d2 = opendir(path); | |
353 | if (d2) { | |
354 | struct dirent* e2; | |
355 | ||
356 | // /var/folders/*/* | |
357 | while ((e2 = readdir(d2))) { | |
8459d725 A |
358 | char dirbuf[PATH_MAX]; |
359 | uid_t owner; | |
360 | gid_t group; | |
34d340d7 | 361 | if (strcmp(e2->d_name, ".") == 0 || strcmp(e2->d_name, "..") == 0) continue; |
8459d725 A |
362 | snprintf(dirbuf, sizeof(dirbuf), |
363 | "%s/%s", path, e2->d_name); | |
364 | if (!is_directory_get_owner_group(dirbuf, &owner, &group)) continue; | |
365 | if (pthread_setugid_np(owner, group) != 0) { | |
366 | asl_log(NULL, NULL, ASL_LEVEL_ERR, | |
367 | "skipping %s: pthread_setugid_np(%u, %u): %s", | |
368 | dirbuf, owner, group, strerror(errno)); | |
369 | continue; | |
370 | } | |
371 | for (i = 0; args->dirs[i]; i++) { | |
372 | const char *name = args->dirs[i]; | |
373 | snprintf(dirbuf, sizeof(dirbuf), | |
ef8ad44b | 374 | "%s/%s/%s", path, e2->d_name, name); |
8459d725 | 375 | if (is_directory(dirbuf)) { |
ef8ad44b A |
376 | // at boot time we clean all files, |
377 | // otherwise only clean regular files. | |
8459d725 | 378 | clean_files_older_than(dirbuf, when); |
ef8ad44b | 379 | } |
34d340d7 | 380 | } |
8459d725 A |
381 | if (pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) != 0) { |
382 | asl_log(NULL, NULL, ASL_LEVEL_ERR, | |
383 | "%s: pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE): %s", | |
384 | dirbuf, strerror(errno)); | |
385 | } | |
34d340d7 | 386 | } |
34d340d7 A |
387 | closedir(d2); |
388 | } else { | |
389 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", path, strerror(errno)); | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
394 | closedir(d); | |
395 | } else { | |
396 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", VAR_FOLDERS_PATH, strerror(errno)); | |
397 | } | |
8459d725 A |
398 | return NULL; |
399 | } | |
400 | ||
401 | void | |
402 | clean_directories(const char* dirs[], int machineBoot) { | |
403 | struct clean_args args; | |
404 | pthread_t t; | |
405 | int ret; | |
406 | #ifdef BOOTDEBUG | |
407 | double ratio; | |
408 | struct mach_timebase_info info; | |
409 | uint64_t begin, end; | |
410 | FILE *debug; | |
411 | ||
412 | mach_timebase_info(&info); | |
413 | ratio = (double)info.numer / ((double)info.denom * NSEC_PER_SEC); | |
414 | begin = mach_absolute_time(); | |
415 | if((debug = fopen("/Debug", "a")) != NULL) { | |
416 | fprintf(debug, "clean_directories: machineBoot=%d\n", machineBoot); | |
417 | } | |
418 | #endif //BOOTDEBUG | |
419 | ||
420 | args.dirs = dirs; | |
421 | args.machineBoot = machineBoot; | |
422 | ret = pthread_create(&t, NULL, clean_thread, &args); | |
423 | if (ret == 0) { | |
424 | ret = pthread_join(t, NULL); | |
425 | if (ret) { | |
426 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "clean_directories: pthread_join: %s", | |
427 | strerror(ret)); | |
428 | } | |
429 | } else { | |
430 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "clean_directories: pthread_create: %s", | |
431 | strerror(ret)); | |
432 | } | |
433 | #ifdef BOOTDEBUG | |
434 | end = mach_absolute_time(); | |
435 | if(debug) { | |
436 | fprintf(debug, "clean_directories: %f secs\n", ratio * (end - begin)); | |
437 | fclose(debug); | |
438 | } | |
439 | #endif //BOOTDEBUG | |
34d340d7 A |
440 | } |
441 | ||
442 | int | |
443 | main(int argc, char* argv[]) { | |
444 | mach_msg_size_t mxmsgsz = MAX_TRAILER_SIZE; | |
445 | kern_return_t kr; | |
446 | long idle_timeout = 30; // default 30 second timeout | |
447 | ||
8459d725 A |
448 | #ifdef BOOTDEBUG |
449 | { | |
450 | FILE *debug; | |
451 | int i; | |
452 | if((debug = fopen("/Debug", "a")) != NULL) { | |
453 | for(i = 0; i < argc; i++) { | |
454 | fprintf(debug, " %s", argv[i]); | |
455 | } | |
456 | fputc('\n', debug); | |
457 | fclose(debug); | |
458 | } | |
459 | } | |
460 | #endif //BOOTDEBUG | |
34d340d7 A |
461 | // Clean up TemporaryItems directory when launched at boot. |
462 | // It is safe to clean all file types at this time. | |
463 | if (argc > 1 && strcmp(argv[1], "-machineBoot") == 0) { | |
ef8ad44b A |
464 | const char *dirs[5]; |
465 | int i = 0; | |
466 | dirs[i++] = DIRHELPER_TEMP_STR; | |
467 | dirs[i++] = "TemporaryItems"; | |
468 | dirs[i++] = "Cleanup At Startup"; | |
469 | if (is_safeboot()) { | |
470 | dirs[i++] = DIRHELPER_CACHE_STR; | |
471 | } | |
472 | dirs[i] = NULL; | |
473 | clean_directories(dirs, 1); | |
34d340d7 A |
474 | exit(EXIT_SUCCESS); |
475 | } else if (argc > 1 && strcmp(argv[1], "-cleanTemporaryItems") == 0) { | |
ef8ad44b A |
476 | const char *dirs[] = { |
477 | DIRHELPER_TEMP_STR, | |
478 | "TemporaryItems", | |
479 | NULL | |
480 | }; | |
481 | clean_directories(dirs, 0); | |
34d340d7 A |
482 | exit(EXIT_SUCCESS); |
483 | } else if (argc > 1) { | |
484 | exit(EXIT_FAILURE); | |
485 | } | |
486 | ||
487 | launch_data_t config = NULL, checkin = NULL; | |
488 | checkin = launch_data_new_string(LAUNCH_KEY_CHECKIN); | |
489 | config = launch_msg(checkin); | |
490 | if (!config || launch_data_get_type(config) == LAUNCH_DATA_ERRNO) { | |
491 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "launchd checkin failed"); | |
492 | exit(EXIT_FAILURE); | |
493 | } | |
494 | ||
495 | launch_data_t tmv; | |
496 | tmv = launch_data_dict_lookup(config, LAUNCH_JOBKEY_TIMEOUT); | |
497 | if (tmv) { | |
fc6d9e4b | 498 | idle_timeout = (long)launch_data_get_integer(tmv); |
34d340d7 A |
499 | asl_log(NULL, NULL, ASL_LEVEL_DEBUG, |
500 | "idle timeout set: %ld seconds", idle_timeout); | |
501 | } | |
502 | ||
503 | launch_data_t svc; | |
504 | svc = launch_data_dict_lookup(config, LAUNCH_JOBKEY_MACHSERVICES); | |
505 | if (!svc) { | |
506 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "no mach services"); | |
507 | exit(EXIT_FAILURE); | |
508 | } | |
509 | ||
510 | svc = launch_data_dict_lookup(svc, DIRHELPER_BOOTSTRAP_NAME); | |
511 | if (!svc) { | |
512 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "no mach service: %s", | |
513 | DIRHELPER_BOOTSTRAP_NAME); | |
514 | exit(EXIT_FAILURE); | |
515 | } | |
516 | ||
517 | mach_port_t mp = launch_data_get_machport(svc); | |
518 | if (mp == MACH_PORT_NULL) { | |
519 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "NULL mach service: %s", | |
520 | DIRHELPER_BOOTSTRAP_NAME); | |
521 | exit(EXIT_FAILURE); | |
522 | } | |
523 | ||
524 | // insert a send right so we can send our idle exit message | |
525 | kr = mach_port_insert_right(mach_task_self(), mp, mp, | |
526 | MACH_MSG_TYPE_MAKE_SEND); | |
527 | if (kr != KERN_SUCCESS) { | |
528 | asl_log(NULL, NULL, ASL_LEVEL_ERR, "send right failed: %s", | |
529 | mach_error_string(kr)); | |
530 | exit(EXIT_FAILURE); | |
531 | } | |
532 | ||
533 | // spawn a thread for our idle timeout | |
534 | pthread_t thread; | |
535 | idle_globals.mp = mp; | |
536 | idle_globals.timeout = idle_timeout; | |
537 | gettimeofday(&idle_globals.lastmsg, NULL); | |
538 | pthread_create(&thread, NULL, &idle_thread, NULL); | |
539 | ||
540 | // look to see if we have any messages queued. if not, assume | |
541 | // we were launched because of the calendar interval, and attempt | |
542 | // to clean the temporary items. | |
543 | mach_msg_type_number_t status_count = MACH_PORT_RECEIVE_STATUS_COUNT; | |
544 | mach_port_status_t status; | |
545 | kr = mach_port_get_attributes(mach_task_self(), mp, | |
546 | MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &status_count); | |
547 | if (kr == KERN_SUCCESS && status.mps_msgcount == 0) { | |
ef8ad44b A |
548 | const char *dirs[] = { |
549 | DIRHELPER_TEMP_STR, | |
550 | "TemporaryItems", | |
551 | NULL | |
552 | }; | |
553 | clean_directories(dirs, 0); | |
554 | exit(EXIT_SUCCESS); | |
34d340d7 A |
555 | } |
556 | ||
557 | // main event loop | |
558 | ||
559 | kr = mach_msg_server(dirhelper_server, mxmsgsz, mp, | |
560 | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | | |
561 | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); | |
562 | if (kr != KERN_SUCCESS) { | |
563 | asl_log(NULL, NULL, ASL_LEVEL_ERR, | |
564 | "mach_msg_server(mp): %s", mach_error_string(kr)); | |
565 | exit(EXIT_FAILURE); | |
566 | } | |
567 | ||
568 | exit(EXIT_SUCCESS); | |
569 | } |