1 /* Copyright 2012-present Facebook, Inc.
2 * Licensed under the Apache License, Version 2.0 */
3 #include "watchman.h"
4 #ifdef __APPLE__
5 #include <launch.h>
6
7 using watchman::FileDescriptor;
8
9 /* When running under launchd, we prefer to obtain our listening
10 * socket from it. We don't strictly need to run this way, but if we didn't,
11 * when the user runs `watchman shutdown-server` the launchd job is left in
12 * a waiting state and needs to be explicitly triggered to get it working
13 * again.
14 * By having the socket registered in our job description, launchd knows
15 * that we want to be activated in this way and takes care of it for us.
16 *
17 * This is made more fun because Yosemite introduces launch_activate_socket()
18 * as a shortcut for this flow and deprecated pretty much everything else
19 * in launch.h. We use the deprecated functions so that we can run on
20 * older releases.
21 * */
22 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
w_get_listener_socket_from_launchd()23 FileDescriptor w_get_listener_socket_from_launchd() {
24 launch_data_t req, resp, socks;
25
26 req = launch_data_new_string(LAUNCH_KEY_CHECKIN);
27 if (req == NULL) {
28 w_log(W_LOG_ERR, "unable to create LAUNCH_KEY_CHECKIN\n");
29 return FileDescriptor();
30 }
31
32 resp = launch_msg(req);
33 launch_data_free(req);
34
35 if (resp == NULL) {
36 w_log(W_LOG_ERR, "launchd checkin failed %s\n", strerror(errno));
37 return FileDescriptor();
38 }
39
40 if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
41 w_log(W_LOG_ERR, "launchd checkin failed: %s\n",
42 strerror(launch_data_get_errno(resp)));
43 launch_data_free(resp);
44 return FileDescriptor();
45 }
46
47 socks = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);
48 if (socks == NULL) {
49 w_log(W_LOG_ERR, "launchd didn't provide any sockets\n");
50 launch_data_free(resp);
51 return FileDescriptor();
52 }
53
54 // the "sock" name here is coupled with the plist in main.c
55 socks = launch_data_dict_lookup(socks, "sock");
56 if (socks == NULL) {
57 w_log(W_LOG_ERR, "launchd: \"sock\" wasn't present in Sockets\n");
58 launch_data_free(resp);
59 return FileDescriptor();
60 }
61
62 return FileDescriptor(
63 launch_data_get_fd(launch_data_array_get_index(socks, 0)));
64 }
65 #endif
66
67 /* vim:ts=2:sw=2:et:
68 */
69