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