예제 #1
0
static void spawn_win32(void) {
  char module_name[WATCHMAN_NAME_MAX];
  GetModuleFileName(NULL, module_name, sizeof(module_name));
  char *argv[MAX_DAEMON_ARGS] = {
    module_name,
    "--foreground",
    NULL
  };
  posix_spawn_file_actions_t actions;
  posix_spawnattr_t attr;
  pid_t pid;
  int i;

  for (i = 0; daemon_argv[i]; i++) {
    append_argv(argv, daemon_argv[i]);
  }

  posix_spawnattr_init(&attr);
  posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP);
  posix_spawn_file_actions_init(&actions);
  posix_spawn_file_actions_addopen(&actions,
      STDIN_FILENO, "/dev/null", O_RDONLY, 0);
  posix_spawn_file_actions_addopen(&actions,
      STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600);
  posix_spawn_file_actions_adddup2(&actions,
      STDOUT_FILENO, STDERR_FILENO);
  posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ);
  posix_spawnattr_destroy(&attr);
  posix_spawn_file_actions_destroy(&actions);
}
예제 #2
0
static void spawn_via_gimli(void)
{
  char *argv[MAX_DAEMON_ARGS] = {
    GIMLI_MONITOR_PATH,
#ifdef WATCHMAN_STATE_DIR
    "--trace-dir=" WATCHMAN_STATE_DIR "/traces",
#endif
    "--pidfile", pid_file,
    "watchman",
    "--foreground",
    NULL
  };
  posix_spawn_file_actions_t actions;
  posix_spawnattr_t attr;
  pid_t pid;
  int i;

  for (i = 0; daemon_argv[i]; i++) {
    append_argv(argv, daemon_argv[i]);
  }

  close_random_fds();

  posix_spawnattr_init(&attr);
  posix_spawn_file_actions_init(&actions);
  posix_spawn_file_actions_addopen(&actions,
      STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600);
  posix_spawn_file_actions_adddup2(&actions,
      STDOUT_FILENO, STDERR_FILENO);
  posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ);
  posix_spawnattr_destroy(&attr);
  posix_spawn_file_actions_destroy(&actions);
}
예제 #3
0
// Spawn watchman via a site-specific spawn helper program.
// We'll pass along any daemon-appropriate arguments that
// we noticed during argument parsing.
static void spawn_site_specific(const char *spawner)
{
  char *argv[MAX_DAEMON_ARGS] = {
    (char*)spawner,
    NULL
  };
  posix_spawn_file_actions_t actions;
  posix_spawnattr_t attr;
  pid_t pid;
  int i;
  int res, err;

  for (i = 0; daemon_argv[i]; i++) {
    append_argv(argv, daemon_argv[i]);
  }

  close_random_fds();

  posix_spawnattr_init(&attr);
  posix_spawn_file_actions_init(&actions);
  posix_spawn_file_actions_addopen(&actions,
      STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600);
  posix_spawn_file_actions_adddup2(&actions,
      STDOUT_FILENO, STDERR_FILENO);
  res = posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ);
  err = errno;

  posix_spawnattr_destroy(&attr);
  posix_spawn_file_actions_destroy(&actions);

  if (res) {
    w_log(W_LOG_FATAL, "Failed to spawn watchman via `%s': %s\n", spawner,
          strerror(err));
  }

  if (waitpid(pid, &res, 0) == -1) {
    w_log(W_LOG_FATAL, "Failed waiting for %s: %s\n", spawner, strerror(errno));
  }

  if (WIFEXITED(res) && WEXITSTATUS(res) == 0) {
    return;
  }

  if (WIFEXITED(res)) {
    w_log(W_LOG_FATAL, "%s: exited with status %d\n", spawner,
          WEXITSTATUS(res));
  } else if (WIFSIGNALED(res)) {
    w_log(W_LOG_FATAL, "%s: signaled with %d\n", spawner, WTERMSIG(res));
  }
  w_log(W_LOG_ERR, "%s: failed to start, exit status %d\n", spawner, res);
}
예제 #4
0
static void spawn_via_launchd(void)
{
  char watchman_path[WATCHMAN_NAME_MAX];
  uint32_t size = sizeof(watchman_path);
  char plist_path[WATCHMAN_NAME_MAX];
  FILE *fp;
  struct passwd *pw;
  uid_t uid;
  char *argv[MAX_DAEMON_ARGS] = {
    "/bin/launchctl",
    "load",
    "-F",
    NULL
  };
  posix_spawnattr_t attr;
  pid_t pid;
  int res;

  close_random_fds();

  if (_NSGetExecutablePath(watchman_path, &size) == -1) {
    w_log(W_LOG_ERR, "_NSGetExecutablePath: path too long; size %u\n", size);
    abort();
  }

  uid = getuid();
  pw = getpwuid(uid);
  if (!pw) {
    w_log(W_LOG_ERR, "getpwuid(%d) failed: %s.  I don't know who you are\n",
        uid, strerror(errno));
    abort();
  }

  snprintf(plist_path, sizeof(plist_path),
      "%s/Library/LaunchAgents", pw->pw_dir);
  // Best effort attempt to ensure that the agents dir exists.  We'll detect
  // and report the failure in the fopen call below.
  mkdir(plist_path, 0755);
  snprintf(plist_path, sizeof(plist_path),
      "%s/Library/LaunchAgents/com.github.facebook.watchman.plist", pw->pw_dir);

  if (access(plist_path, R_OK) == 0) {
    // Unload any that may already exist, as it is likely wrong
    char *unload_argv[MAX_DAEMON_ARGS] = {
      "/bin/launchctl",
      "unload",
      NULL
    };
    append_argv(unload_argv, plist_path);

    errno = posix_spawnattr_init(&attr);
    if (errno != 0) {
      w_log(W_LOG_FATAL, "posix_spawnattr_init: %s\n", strerror(errno));
    }

    res = posix_spawnp(&pid, unload_argv[0], NULL, &attr, unload_argv, environ);
    if (res == 0) {
      waitpid(pid, &res, 0);
    }
    posix_spawnattr_destroy(&attr);

    // Forcibly remove the plist.  In some cases it may have some attributes
    // set that prevent launchd from loading it.  This can happen where
    // the system was re-imaged or restored from a backup
    unlink(plist_path);
  }

  fp = fopen(plist_path, "w");
  if (!fp) {
    w_log(W_LOG_ERR, "Failed to open %s for write: %s\n",
        plist_path, strerror(errno));
    abort();
  }

  compute_file_name(&pid_file, compute_user_name(), "pid", "pidfile");

  fprintf(fp,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n"
"<dict>\n"
"    <key>Label</key>\n"
"    <string>com.github.facebook.watchman</string>\n"
"    <key>Disabled</key>\n"
"    <false/>\n"
"    <key>ProgramArguments</key>\n"
"    <array>\n"
"        <string>%s</string>\n"
"        <string>--foreground</string>\n"
"        <string>--logfile=%s</string>\n"
"        <string>--log-level=%d</string>\n"
"        <string>--sockname=%s</string>\n"
"        <string>--statefile=%s</string>\n"
"        <string>--pidfile=%s</string>\n"
"    </array>\n"
"    <key>Sockets</key>\n"
"    <dict>\n"
"        <key>sock</key>\n" // coupled with get_listener_socket_from_launchd
"        <dict>\n"
"            <key>SockPathName</key>\n"
"            <string>%s</string>\n"
"            <key>SockPathMode</key>\n"
"            <integer>%d</integer>\n"
"        </dict>\n"
"    </dict>\n"
"    <key>KeepAlive</key>\n"
"    <dict>\n"
"        <key>Crashed</key>\n"
"        <true/>\n"
"    </dict>\n"
"    <key>RunAtLoad</key>\n"
"    <true/>\n"
"    <key>EnvironmentVariables</key>\n"
"    <dict>\n"
"        <key>PATH</key>\n"
"        <string><![CDATA[%s]]></string>\n"
"    </dict>\n"
"    <key>ProcessType</key>\n"
"    <string>Interactive</string>\n"
"    <key>Nice</key>\n"
"    <integer>-5</integer>\n"
"</dict>\n"
"</plist>\n",
    watchman_path, log_name, log_level, sock_name,
    watchman_state_file, pid_file, sock_name, 0600,
    getenv("PATH"));
  fclose(fp);
  // Don't rely on umask, ensure we have the correct perms
  chmod(plist_path, 0644);

  append_argv(argv, plist_path);

  errno = posix_spawnattr_init(&attr);
  if (errno != 0) {
    w_log(W_LOG_FATAL, "posix_spawnattr_init: %s\n", strerror(errno));
  }

  res = posix_spawnp(&pid, argv[0], NULL, &attr, argv, environ);
  if (res) {
    w_log(W_LOG_FATAL, "Failed to spawn watchman via launchd: %s\n",
        strerror(errno));
  }
  posix_spawnattr_destroy(&attr);

  if (waitpid(pid, &res, 0) == -1) {
    w_log(W_LOG_FATAL, "Failed waiting for launchctl load: %s\n",
        strerror(errno));
  }

  if (WIFEXITED(res) && WEXITSTATUS(res) == 0) {
    return;
  }

  // Most likely cause is "headless" operation with no GUI context
  if (WIFEXITED(res)) {
    w_log(W_LOG_ERR, "launchctl: exited with status %d\n", WEXITSTATUS(res));
  } else if (WIFSIGNALED(res)) {
    w_log(W_LOG_ERR, "launchctl: signaled with %d\n", WTERMSIG(res));
  }
  w_log(W_LOG_ERR, "Falling back to daemonize\n");
  daemonize();
}
예제 #5
0
파일: main.c 프로젝트: Kingside/watchman
static void spawn_via_launchd(void)
{
  char watchman_path[WATCHMAN_NAME_MAX];
  uint32_t size = sizeof(watchman_path);
  char plist_path[WATCHMAN_NAME_MAX];
  FILE *fp;
  struct passwd *pw;
  uid_t uid;
  char *argv[MAX_DAEMON_ARGS] = {
    "/bin/launchctl",
    "load",
    "-F",
    NULL
  };
  posix_spawnattr_t attr;
  pid_t pid;
  int res;

  if (_NSGetExecutablePath(watchman_path, &size) == -1) {
    w_log(W_LOG_ERR, "_NSGetExecutablePath: path too long; size %u\n", size);
    abort();
  }

  uid = getuid();
  pw = getpwuid(uid);
  if (!pw) {
    w_log(W_LOG_ERR, "getpwuid(%d) failed: %s.  I don't know who you are\n",
        uid, strerror(errno));
    abort();
  }

  snprintf(plist_path, sizeof(plist_path),
      "%s/Library/LaunchAgents", pw->pw_dir);
  // Best effort attempt to ensure that the agents dir exists.  We'll detect
  // and report the failure in the fopen call below.
  mkdir(plist_path, 0755);
  snprintf(plist_path, sizeof(plist_path),
      "%s/Library/LaunchAgents/com.github.facebook.watchman.plist", pw->pw_dir);

  fp = fopen(plist_path, "w");
  if (!fp) {
    w_log(W_LOG_ERR, "Failed to open %s for write: %s\n",
        plist_path, strerror(errno));
    abort();
  }

  fprintf(fp,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n"
"<dict>\n"
"    <key>Label</key>\n"
"    <string>com.github.facebook.watchman</string>\n"
"    <key>Disabled</key>\n"
"    <false/>\n"
"    <key>ProgramArguments</key>\n"
"    <array>\n"
"        <string>%s</string>\n"
"        <string>--foreground</string>\n"
"        <string>--logfile=%s</string>\n"
"        <string>--sockname=%s</string>\n"
"        <string>--statefile=%s</string>\n"
"    </array>\n"
"    <key>Sockets</key>\n"
"    <dict>\n"
"        <key>sock</key>\n" // coupled with get_listener_socket_from_launchd
"        <dict>\n"
"            <key>SockPathName</key>\n"
"            <string>%s</string>\n"
"        </dict>\n"
"    </dict>\n"
"    <key>KeepAlive</key>\n"
"    <dict>\n"
"        <key>Crashed</key>\n"
"        <true/>\n"
"    </dict>\n"
"    <key>RunAtLoad</key>\n"
"    <false/>\n"
"</dict>\n"
"</plist>\n",
    watchman_path, log_name, sock_name, watchman_state_file, sock_name);
  fclose(fp);

  append_argv(argv, plist_path);

  errno = posix_spawnattr_init(&attr);
  if (errno != 0) {
    w_log(W_LOG_FATAL, "posix_spawnattr_init: %s\n", strerror(errno));
  }

  res = posix_spawnp(&pid, argv[0], NULL, &attr, argv, environ);
  if (res) {
    w_log(W_LOG_FATAL, "Failed to spawn watchman via launchd: %s\n",
        strerror(errno));
  }
  posix_spawnattr_destroy(&attr);

  if (waitpid(pid, &res, 0) == -1) {
    w_log(W_LOG_FATAL, "Failed waiting for launchctl load: %s\n",
        strerror(errno));
  }

  if (WIFEXITED(res) && WEXITSTATUS(res) == 0) {
    return;
  }

  // Most likely cause is "headless" operation with no GUI context
  if (WIFEXITED(res)) {
    w_log(W_LOG_ERR, "launchctl: exited with status %d\n", WEXITSTATUS(res));
  } else if (WIFSIGNALED(res)) {
    w_log(W_LOG_ERR, "launchctl: signalled with %d\n", WTERMSIG(res));
  }
  w_log(W_LOG_ERR, "Falling back to daemonize\n");
  daemonize();
}