static FileDescriptor get_listener_unix_domain_socket()

in watchman/listener.cpp [73:164]


static FileDescriptor get_listener_unix_domain_socket(const char* path) {
#ifndef _WIN32
  mode_t perms = cfg_get_perms(
      "sock_access", true /* write bits */, false /* execute bits */);
#endif
  FileDescriptor listener_fd;

#ifdef __APPLE__
  listener_fd = w_get_listener_socket_from_launchd();
  if (listener_fd) {
    logf(ERR, "Using socket from launchd as listening socket\n");
    return listener_fd;
  }
#endif

  struct sockaddr_un un {};
  if (strlen(path) >= sizeof(un.sun_path) - 1) {
    logf(ERR, "{}: path is too long\n", path);
    return FileDescriptor();
  }

  listener_fd = FileDescriptor(
      ::socket(PF_LOCAL, SOCK_STREAM, 0),
      "socket",
      FileDescriptor::FDType::Socket);

  un.sun_family = PF_LOCAL;
  memcpy(un.sun_path, path, strlen(path) + 1);

  (void)unlink(path);
  if (::bind(listener_fd.system_handle(), (struct sockaddr*)&un, sizeof(un)) !=
      0) {
    logf(ERR, "bind({}): {}\n", path, folly::errnoStr(errno));
    return FileDescriptor();
  }

#ifndef _WIN32
  // The permissions in the containing directory should be correct, so this
  // should be correct as well. But set the permissions in any case.
  if (chmod(path, perms) == -1) {
    logf(ERR, "chmod({}, {:o}): {}", path, perms, folly::errnoStr(errno));
    return FileDescriptor();
  }

  // Double-check that the socket has the right permissions. This can happen
  // when the containing directory was created in a previous run, with a group
  // the user is no longer in.
  struct stat st;
  if (lstat(path, &st) == -1) {
    watchman::log(
        watchman::ERR, "lstat(", path, "): ", folly::errnoStr(errno), "\n");
    return FileDescriptor();
  }

  // This is for testing only
  // (test_sock_perms.py:test_user_previously_in_sock_group). Do not document.
  const char* sock_group_name = cfg_get_string("__sock_file_group", nullptr);
  if (!sock_group_name) {
    sock_group_name = cfg_get_string("sock_group", nullptr);
  }

  if (sock_group_name) {
    const struct group* sock_group = w_get_group(sock_group_name);
    if (!sock_group) {
      return FileDescriptor();
    }
    if (st.st_gid != sock_group->gr_gid) {
      watchman::log(
          watchman::ERR,
          "for socket '",
          path,
          "', gid ",
          st.st_gid,
          " doesn't match expected gid ",
          sock_group->gr_gid,
          " (group name ",
          sock_group_name,
          "). Ensure that you are still a member of group ",
          sock_group_name,
          ".\n");
      return FileDescriptor();
    }
  }
#endif

  if (::listen(listener_fd.system_handle(), 200) != 0) {
    logf(ERR, "listen({}): {}\n", path, folly::errnoStr(errno));
    return FileDescriptor();
  }

  return listener_fd;
}