Example #1
0
static void cmd_shutdown(struct watchman_client *client, json_t *args) {
  json_t *resp = make_response();
  unused_parameter(args);

  w_log(W_LOG_ERR, "shutdown-server was requested, exiting!\n");
  w_request_shutdown();

  set_prop(resp, "shutdown-server", json_true());
  send_and_dispose_response(client, resp);
}
Example #2
0
/* watch-list
 * Returns a list of watched roots */
static void cmd_watch_list(struct watchman_client *client, json_t *args)
{
  json_t *resp;
  json_t *root_paths;
  unused_parameter(args);

  resp = make_response();
  root_paths = w_root_watch_list_to_json();
  set_prop(resp, "roots", root_paths);
  send_and_dispose_response(client, resp);
}
Example #3
0
static bool kqueue_root_consume_notify(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_pending_collection *coll)
{
  struct kqueue_root_state *state = root->watch;
  int n;
  int i;
  struct timespec ts = { 0, 0 };
  struct timeval now;
  unused_parameter(watcher);

  errno = 0;

  w_log(W_LOG_DBG, "kqueue(%s)\n", root->root_path->buf);
  n = kevent(state->kq_fd, NULL, 0,
      state->keventbuf, sizeof(state->keventbuf) / sizeof(state->keventbuf[0]),
      &ts);
  w_log(W_LOG_DBG, "consume_kqueue: %s n=%d err=%s\n",
      root->root_path->buf, n, strerror(errno));
  if (root->cancelled) {
    return 0;
  }

  gettimeofday(&now, NULL);
  for (i = 0; n > 0 && i < n; i++) {
    uint32_t fflags = state->keventbuf[i].fflags;

    if (IS_DIR_BIT_SET(state->keventbuf[i].udata)) {
      struct watchman_dir *dir = DECODE_DIR(state->keventbuf[i].udata);

      w_log(W_LOG_DBG, " KQ dir %s [0x%x]\n", dir->path->buf, fflags);
      if ((fflags & (NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE)) &&
          w_string_equal(dir->path, root->root_path)) {
        w_log(W_LOG_ERR,
            "root dir %s has been (re)moved [code 0x%x], canceling watch\n",
            root->root_path->buf, fflags);
        w_root_cancel(root);
        return 0;
      }
      w_pending_coll_add(coll, dir->path, false, now, false);
    } else {
      // NetBSD defines udata as intptr type, so the cast is necessary
      struct watchman_file *file = (void *)state->keventbuf[i].udata;

      w_string_t *path;

      path = w_string_path_cat(file->parent->path, file->name);
      w_pending_coll_add(coll, path, true, now, true);
      w_log(W_LOG_DBG, " KQ file %.*s [0x%x]\n", path->len, path->buf, fflags);
      w_string_delref(path);
    }
  }

  return n > 0;
}
Example #4
0
w_query_expr *w_expr_imatch_parser(w_query *query, json_t *term)
{
#ifdef NO_CASELESS_FNMATCH
  unused_parameter(term);
  asprintf(&query->errmsg,
      "imatch: Your system doesn't support FNM_CASEFOLD");
  return NULL;
#else
  return match_parser(query, term, true);
#endif
}
Example #5
0
/* version */
void cmd_version(struct watchman_client *client, json_t *args)
{
  json_t *resp = make_response();

  unused_parameter(args);

#ifdef WATCHMAN_BUILD_INFO
  set_prop(resp, "buildinfo", json_string(WATCHMAN_BUILD_INFO));
#endif

  send_and_dispose_response(client, resp);
}
Example #6
0
static bool kqueue_root_start_watch_file(watchman_global_watcher_t watcher,
      w_root_t *root, struct watchman_file *file) {
  struct kqueue_root_state *state = root->watch;
  struct kevent k;
  w_ht_val_t fdval;
  int fd;
  w_string_t *full_name;
  unused_parameter(watcher);

  full_name = w_string_path_cat(file->parent->path, file->name);
  pthread_mutex_lock(&state->lock);
  if (w_ht_lookup(state->name_to_fd, w_ht_ptr_val(full_name), &fdval, false)) {
    // Already watching it
    pthread_mutex_unlock(&state->lock);
    return true;
  }
  pthread_mutex_unlock(&state->lock);

  w_log(W_LOG_DBG, "watch_file(%s)\n", full_name->buf);

  fd = open(full_name->buf, O_EVTONLY|O_CLOEXEC);
  if (fd == -1) {
    w_log(W_LOG_ERR, "failed to open %s O_EVTONLY: %s\n",
        full_name->buf, strerror(errno));
    w_string_delref(full_name);
    return false;
  }

  memset(&k, 0, sizeof(k));
  EV_SET(&k, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR,
      NOTE_WRITE|NOTE_DELETE|NOTE_EXTEND|NOTE_RENAME|NOTE_ATTRIB,
      0, full_name);

  pthread_mutex_lock(&state->lock);
  w_ht_replace(state->name_to_fd, w_ht_ptr_val(full_name), fd);
  w_ht_replace(state->fd_to_name, fd, w_ht_ptr_val(full_name));
  pthread_mutex_unlock(&state->lock);

  if (kevent(state->kq_fd, &k, 1, NULL, 0, 0)) {
    w_log(W_LOG_DBG, "kevent EV_ADD file %s failed: %s",
        full_name->buf, strerror(errno));
    close(fd);
    pthread_mutex_lock(&state->lock);
    w_ht_del(state->name_to_fd, w_ht_ptr_val(full_name));
    w_ht_del(state->fd_to_name, fd);
    pthread_mutex_unlock(&state->lock);
  } else {
    w_log(W_LOG_DBG, "kevent file %s -> %d\n", full_name->buf, fd);
  }
  w_string_delref(full_name);

  return true;
}
Example #7
0
static void portfs_root_stop_watch_file(watchman_global_watcher_t watcher,
      w_root_t *root, struct watchman_file *file) {
  struct portfs_root_state *state = root->watch;
  unused_parameter(watcher);

  port_dissociate(state->port_fd, PORT_SOURCE_FILE,
      (uintptr_t)&file->port_file);
  if (file->port_file.fo_name) {
    free(file->port_file.fo_name);
    file->port_file.fo_name = NULL;
  }
}
Example #8
0
static bool eval_size(struct w_query_ctx *ctx, struct watchman_file *file,
    void *data)
{
  struct w_query_int_compare *comp = data;
  unused_parameter(ctx);

  // Removed files never evaluate true
  if (!file->exists) {
    return false;
  }

  return eval_int_compare(file->stat.size, comp);
}
Example #9
0
void kqueue_root_dtor(watchman_global_watcher_t watcher, w_root_t *root) {
  struct kqueue_root_state *state = root->watch;
  unused_parameter(watcher);

  if (!state) {
    return;
  }

  close(state->kq_fd);
  state->kq_fd = -1;

  free(state);
  root->watch = NULL;
}
Example #10
0
static DIR *winwatch_root_start_watch_dir(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_dir *dir, struct timeval now,
    const char *path) {
  DIR *osdir;
  unused_parameter(watcher);

  osdir = opendir(path);
  if (!osdir) {
    handle_open_errno(root, dir, now, "opendir", errno, strerror(errno));
    return NULL;
  }

  return osdir;
}
Example #11
0
static bool kqueue_root_wait_notify(watchman_global_watcher_t watcher,
    w_root_t *root, int timeoutms) {
  struct kqueue_root_state *state = root->watch;
  int n;
  struct pollfd pfd;
  unused_parameter(watcher);

  pfd.fd = state->kq_fd;
  pfd.events = POLLIN;

  n = poll(&pfd, 1, timeoutms);

  return n == 1;
}
Example #12
0
static void crash_handler(int signo, siginfo_t *si, void *ucontext) {
  const char *reason = "";
  unused_parameter(ucontext);
  if (si) {
    switch (si->si_signo) {
      case SIGILL:
        switch (si->si_code) {
          case ILL_ILLOPC: reason = "illegal opcode"; break;
          case ILL_ILLOPN: reason = "illegal operand"; break;
          case ILL_ILLADR: reason = "illegal addressing mode"; break;
          case ILL_ILLTRP: reason = "illegal trap"; break;
          case ILL_PRVOPC: reason = "privileged opcode"; break;
          case ILL_PRVREG: reason = "privileged register"; break;
          case ILL_COPROC: reason = "co-processor error"; break;
          case ILL_BADSTK: reason = "internal stack error"; break;
        }
        break;
      case SIGFPE:
        switch (si->si_code) {
          case FPE_INTDIV: reason = "integer divide by zero"; break;
          case FPE_INTOVF: reason = "integer overflow"; break;
          case FPE_FLTDIV: reason = "floating point divide by zero"; break;
          case FPE_FLTOVF: reason = "floating point overflow"; break;
          case FPE_FLTUND: reason = "floating point underflow"; break;
          case FPE_FLTRES: reason = "floating point inexact result"; break;
          case FPE_FLTINV: reason = "invalid floating point operation"; break;
          case FPE_FLTSUB: reason = "subscript out of range"; break;
        }
        break;
      case SIGSEGV:
        switch (si->si_code) {
          case SEGV_MAPERR: reason = "address not mapped to object"; break;
          case SEGV_ACCERR: reason = "invalid permissions for mapped object";
                            break;
        }
        break;
#ifdef SIGBUS
      case SIGBUS:
        switch (si->si_code) {
          case BUS_ADRALN: reason = "invalid address alignment"; break;
          case BUS_ADRERR: reason = "non-existent physical address"; break;
        }
        break;
#endif
    }
  }
  w_log(W_LOG_FATAL, "Terminating due to signal %d %s. %s (%p)\n",
      signo, strsignal(signo), reason, si ? si->si_value.sival_ptr : NULL);
}
Example #13
0
static void cmd_shutdown(
    struct watchman_client *client,
    json_t *args)
{
  json_t *resp = make_response();
  unused_parameter(args);

  w_log(W_LOG_ERR, "shutdown-server was requested, exiting!\n");
  stopping = true;

  // Knock listener thread out of poll/accept
  pthread_kill(listener_thread, SIGUSR1);

  set_prop(resp, "shutdown-server", json_true());
  send_and_dispose_response(client, resp);
}
Example #14
0
static void kqueue_root_stop_watch_file(watchman_global_watcher_t watcher,
      w_root_t *root, struct watchman_file *file) {
  struct kqueue_root_state *state = root->watch;
  struct kevent k;
  unused_parameter(watcher);

  if (file->kq_fd == -1) {
    return;
  }

  memset(&k, 0, sizeof(k));
  EV_SET(&k, file->kq_fd, EVFILT_VNODE, EV_DELETE, 0, 0, file);
  kevent(state->kq_fd, &k, 1, NULL, 0, 0);
  close(file->kq_fd);
  file->kq_fd = -1;
}
Example #15
0
void kqueue_root_dtor(watchman_global_watcher_t watcher, w_root_t *root) {
  struct kqueue_root_state *state = root->watch;
  unused_parameter(watcher);

  if (!state) {
    return;
  }

  pthread_mutex_destroy(&state->lock);
  close(state->kq_fd);
  state->kq_fd = -1;
  w_ht_free(state->name_to_fd);
  w_ht_free(state->fd_to_name);

  free(state);
  root->watch = NULL;
}
Example #16
0
static void *child_reaper(void *arg)
{
  sigset_t sigset;
  unused_parameter(arg);

  // Unblock SIGCHLD only in this thread
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGCHLD);
  pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);

  while (!stopping) {
    usleep(200000);
    w_reap_children(true);
  }

  return 0;
}
Example #17
0
static bool default_generators(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    void *gendata)
{
  bool generated = false;

  unused_parameter(gendata);

  // Time based query
  if (ctx->since.is_timestamp || !ctx->since.clock.is_fresh_instance) {
    if (!time_generator(query, root, ctx)) {
      return false;
    }
    generated = true;
  }

  // Suffix
  if (query->suffixes) {
    if (!suffix_generator(query, root, ctx)) {
      return false;
    }
    generated = true;
  }

  if (query->npaths) {
    if (!path_generator(query, root, ctx)) {
      return false;
    }
    generated = true;
  }

  // And finally, if there were no other generators, we walk all known
  // files
  if (!generated) {
    if (!all_files_generator(query, root, ctx)) {
      return false;
    }
  }

  return true;
}
Example #18
0
static struct watchman_dir_handle *inot_root_start_watch_dir(
    watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_dir *dir, struct timeval now,
    const char *path) {
  struct inot_root_state *state = root->watch;
  struct watchman_dir_handle *osdir = NULL;
  int newwd, err;
  unused_parameter(watcher);

  // Carry out our very strict opendir first to ensure that we're not
  // traversing symlinks in the context of this root
  osdir = w_dir_open(path);
  if (!osdir) {
    handle_open_errno(root, dir, now, "opendir", errno, NULL);
    return NULL;
  }

  // The directory might be different since the last time we looked at it, so
  // call inotify_add_watch unconditionally.
  newwd = inotify_add_watch(state->infd, path, WATCHMAN_INOTIFY_MASK);
  if (newwd == -1) {
    err = errno;
    if (errno == ENOSPC || errno == ENOMEM) {
      // Limits exceeded, no recovery from our perspective
      set_poison_state(root, dir->path, now, "inotify-add-watch", errno,
          inot_strerror(errno));
    } else {
      handle_open_errno(root, dir, now, "inotify_add_watch", errno,
          inot_strerror(errno));
    }
    w_dir_close(osdir);
    errno = err;
    return NULL;
  }

  // record mapping
  pthread_mutex_lock(&state->lock);
  w_ht_replace(state->wd_to_name, newwd, w_ht_ptr_val(dir->path));
  pthread_mutex_unlock(&state->lock);
  w_log(W_LOG_DBG, "adding %d -> %s mapping\n", newwd, path);

  return osdir;
}
Example #19
0
void winwatch_root_dtor(watchman_global_watcher_t watcher, w_root_t *root) {
  struct winwatch_root_state *state = root->watch;
  unused_parameter(watcher);

  if (!state) {
    return;
  }

  // wait for readchanges_thread to quit before we tear down state
  if (!pthread_equal(state->thread, pthread_self())) {
    void *ignore;
    pthread_join(state->thread, &ignore);
  }

  CloseHandle(state->ping);
  CloseHandle(state->olap);
  CloseHandle(state->dir_handle);

  free(state);
  root->watch = NULL;
}
Example #20
0
static bool eval_dirname(struct w_query_ctx *ctx,
                         struct watchman_file *file, void *ptr) {
    struct dirname_data *data = ptr;
    w_string_t *str = w_query_ctx_get_wholename(ctx);
    json_int_t depth = 0;
    size_t i;

    unused_parameter(file);

    if (str->len <= data->dirname->len) {
        // Either it doesn't prefix match, or file name is == dirname.
        // That means that the best case is that the wholename matches.
        // we only want to match if dirname(wholename) matches, so it
        // is not possible for us to match unless the length of wholename
        // is greater than the dirname operand
        return false;
    }

    // Want to make sure that wholename is a child of dirname, so
    // check for a dir separator.  Special case for dirname == '' (the root),
    // which won't have a slash in position 0.
    if (data->dirname->len > 0 && str->buf[data->dirname->len] != '/') {
        // may have a common prefix with, but is not a child of dirname
        return false;
    }

    if (!data->startswith(str, data->dirname)) {
        return false;
    }

    // Now compute the depth of file from dirname.  We do this by
    // counting dir separators, not including the one we saw above.
    for (i = data->dirname->len + 1; i < str->len; i++) {
        if (str->buf[i] == '/') {
            depth++;
        }
    }

    return eval_int_compare(depth, &data->depth);
}
Example #21
0
static DIR *portfs_root_start_watch_dir(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_dir *dir, struct timeval now,
    const char *path) {
  struct portfs_root_state *state = root->watch;
  DIR *osdir;
  struct stat st;
  unused_parameter(watcher);

  osdir = opendir_nofollow(path);
  if (!osdir) {
    handle_open_errno(root, dir, now, "opendir", errno, NULL);
    return NULL;
  }

  if (fstat(dirfd(osdir), &st) == -1) {
    // whaaa?
    w_log(W_LOG_ERR, "fstat on opened dir %s failed: %s\n", path,
        strerror(errno));
    w_root_schedule_recrawl(root, "fstat failed");
    closedir(osdir);
    return NULL;
  }

  dir->port_file.fo_mtime = st.st_atim;
  dir->port_file.fo_mtime = st.st_mtim;
  dir->port_file.fo_ctime = st.st_ctim;
  dir->port_file.fo_name = (char*)dir->path->buf;

  errno = 0;
  if (port_associate(state->port_fd, PORT_SOURCE_FILE,
        (uintptr_t)&dir->port_file, WATCHMAN_PORT_EVENTS,
        SET_DIR_BIT(dir))) {
    w_log(W_LOG_ERR, "port_associate %s %s\n",
        dir->port_file.fo_name, strerror(errno));
  }

  return osdir;
}
Example #22
0
static bool winwatch_root_wait_notify(watchman_global_watcher_t watcher,
    w_root_t *root, int timeoutms) {
  struct winwatch_root_state *state = root->watch;
  struct timeval now, delta, target;
  struct timespec ts;
  unused_parameter(watcher);

  if (timeoutms == 0 || state->head) {
    return state->head ? true : false;
  }

  // Add timeout to current time, convert to absolute timespec
  gettimeofday(&now, NULL);
  delta.tv_sec = timeoutms / 1000;
  delta.tv_usec = (timeoutms - (delta.tv_sec * 1000)) * 1000;
  w_timeval_add(now, delta, &target);
  w_timeval_to_timespec(target, &ts);

  pthread_mutex_lock(&state->mtx);
  pthread_cond_timedwait(&state->cond, &state->mtx, &ts);
  pthread_mutex_unlock(&state->mtx);
  return state->head ? true : false;
}
Example #23
0
bool kqueue_root_init(watchman_global_watcher_t watcher, w_root_t *root,
    char **errmsg) {
  struct kqueue_root_state *state;
  unused_parameter(watcher);

  state = calloc(1, sizeof(*state));
  if (!state) {
    *errmsg = strdup("out of memory");
    return false;
  }
  root->watch = state;

  state->kq_fd = kqueue();
  if (state->kq_fd == -1) {
    ignore_result(asprintf(errmsg, "watch(%.*s): kqueue() error: %s",
        root->root_path->len, root->root_path->buf, strerror(errno)));
    w_log(W_LOG_ERR, "%s\n", *errmsg);
    return false;
  }
  w_set_cloexec(state->kq_fd);

  return true;
}
Example #24
0
static void kqueue_root_stop_watch_dir(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_dir *dir) {
  struct kqueue_root_state *state = root->watch;
  struct kevent k;
  unused_parameter(watcher);

  if (dir->wd == -1) {
    return;
  }

  memset(&k, 0, sizeof(k));
  EV_SET(&k, dir->wd, EVFILT_VNODE, EV_DELETE,
      0, 0, SET_DIR_BIT(dir));

  if (kevent(state->kq_fd, &k, 1, NULL, 0, 0)) {
    w_log(W_LOG_ERR, "rm_watch: %d %.*s %s\n",
        dir->wd, dir->path->len, dir->path->buf,
        strerror(errno));
    w_root_schedule_recrawl(root, "rm_watch failed");
  }

  close(dir->wd);
  dir->wd = -1;
}
Example #25
0
void inot_root_dtor(watchman_global_watcher_t watcher, w_root_t *root) {
  struct inot_root_state *state = root->watch;
  unused_parameter(watcher);

  if (!state) {
    return;
  }

  pthread_mutex_destroy(&state->lock);

  close(state->infd);
  state->infd = -1;
  if (state->wd_to_name) {
    w_ht_free(state->wd_to_name);
    state->wd_to_name = NULL;
  }
  if (state->move_map) {
    w_ht_free(state->move_map);
    state->move_map = NULL;
  }

  free(state);
  root->watch = NULL;
}
Example #26
0
static void *child_reaper(void *arg)
{
#ifndef _WIN32
  sigset_t sigset;

  // By default, keep both SIGCHLD and SIGUSR1 blocked
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGUSR1);
  sigaddset(&sigset, SIGCHLD);
  pthread_sigmask(SIG_BLOCK, &sigset, NULL);

  // SIGCHLD is ordinarily blocked, so we listen for it only in
  // sigsuspend, when we're also listening for the SIGUSR1 that tells
  // us to exit.
  pthread_sigmask(SIG_BLOCK, NULL, &sigset);
  sigdelset(&sigset, SIGCHLD);
  sigdelset(&sigset, SIGUSR1);

#endif
  unused_parameter(arg);
  w_set_thread_name("child_reaper");

#ifdef _WIN32
  while (!stopping) {
    usleep(200000);
    w_reap_children(true);
  }
#else
  while (!stopping) {
    w_reap_children(false);
    sigsuspend(&sigset);
  }
#endif

  return 0;
}
Example #27
0
// This is just a placeholder.
// This catches SIGUSR1 so we don't terminate.
// We use this to interrupt blocking syscalls
// on the worker threads
static void wakeme(int signo)
{
  unused_parameter(signo);
}
Example #28
0
void kqueue_global_dtor(watchman_global_watcher_t watcher) {
  unused_parameter(watcher);
}
Example #29
0
static void kqueue_file_free(watchman_global_watcher_t watcher,
    struct watchman_file *file) {
  unused_parameter(watcher);
  unused_parameter(file);
}
Example #30
0
static void kqueue_root_signal_threads(watchman_global_watcher_t watcher,
    w_root_t *root) {
  unused_parameter(watcher);
  unused_parameter(root);
}