Пример #1
0
static int
watchman_read_and_handle_errors(struct watchman_connection *conn,
                                struct watchman_error *error)
{
    proto_t obj = watchman_read(conn, error);
    if (proto_is_null(obj)) {
        return 1;
    }
    if (!proto_is_object(obj)) {
        char *bogus_text = proto_dumps(obj, 0);
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got non-object result from watchman : %s",
                     bogus_text);
        free(bogus_text);
        proto_free(obj);
        return 1;
    }
    proto_t error_node = proto_object_get(obj, "error");
    if (!proto_is_null(error_node)) {
        watchman_err(error, WATCHMAN_ERR_OTHER,
                     "Got error result from watchman : %s",
                     proto_strdup(error_node));
        proto_free(obj);
        return 1;
    }

    proto_free(obj);
    return 0;
}
Пример #2
0
static int
watchman_send_simple_command(struct watchman_connection *conn,
                             struct watchman_error *error, ...)
{
    int result = 0;
    json_t *cmd_array = json_array();
    va_list argptr;
    va_start(argptr, error);
    char *arg;
    while ((arg = va_arg(argptr, char *))) {
        json_array_append_new(cmd_array, json_string(arg));
    }
    if (use_bser_encoding) {
        result = bser_write_to_file(cmd_array, conn->fp) == 0;
    } else {
        result = json_dumpf(cmd_array, conn->fp, JSON_COMPACT);
        fputc('\n', conn->fp);
    }
    if (result) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                         "Timeout sending simple watchman command");
        } else {
            watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                         "Failed to send simple watchman command");
        }
        result = 1;
    }

    json_decref(cmd_array);
    return result;
}
Пример #3
0
int watchman_pclose(struct watchman_error *error, struct watchman_popen *popen)
{
    close(popen->fd);

    int status;
    int pid = waitpid(popen->pid, &status, 0);
    if (pid < 0) {
        watchman_err(error, WATCHMAN_ERR_RUN_WATCHMAN, get_sockname_msg,
                     strerror(errno));
        return -1;
    }

    switch(WEXITSTATUS(status)) {
    case 0:
        return 0;
    case WATCHMAN_EXEC_FAILED:
        watchman_err(error, WATCHMAN_ERR_RUN_WATCHMAN, get_sockname_msg,
                     strerror(errno));
        return -1;
    case WATCHMAN_EXEC_INTERNAL_ERROR:
        watchman_err(error, WATCHMAN_ERR_OTHER, get_sockname_msg,
                     strerror(errno));
        return -1;
    default:
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN, get_sockname_msg,
                     strerror(errno));
        return -1;
    }
}
Пример #4
0
struct watchman_connection *
watchman_sock_connect(struct watchman_error *error, const char *sockname)
{
    struct sockaddr_un addr = { };

    int fd;
    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        watchman_err(error, "Socket error %s", strerror(errno));
        return NULL;
    }

    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sockname, sizeof(addr.sun_path) - 1);

    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
        close(fd);
        watchman_err(error, "Connect error %s", strerror(errno));
        return NULL;
    }

    FILE *sockfp = fdopen(fd, "r+");
    if (!sockfp) {
        close(fd);
        watchman_err(error,
                     "Failed to connect to watchman socket %s: %s.",
                     sockname, strerror(errno));
        return NULL;
    }
    setlinebuf(sockfp);

    struct watchman_connection *conn = malloc(sizeof(*conn));
    conn->fp = sockfp;
    return conn;
}
Пример #5
0
static int
watchman_read_and_handle_errors(struct watchman_connection *conn,
                                struct watchman_error *error)
{
    json_t *obj = watchman_read(conn, error);
    if (!obj) {
        return 1;
    }
    if (!json_is_object(obj)) {
        char *bogus_json_text = json_dumps(obj, 0);
        watchman_err(error, "Got non-object result from watchman : %s",
                     bogus_json_text);
        free(bogus_json_text);
        json_decref(obj);
        return 1;
    }
    json_t *error_json = json_object_get(obj, "error");
    if (error_json) {
        watchman_err(error, "Got error result from watchman : %s",
                     json_string_value(error_json));
        json_decref(obj);
        return 1;
    }

    json_decref(obj);
    return 0;
}
Пример #6
0
static int
watchman_send(struct watchman_connection *conn,
              json_t *query, struct watchman_error *error)
{
    int result;
    if (use_bser_encoding) {
        result = bser_write_to_file(query, conn->fp) == 0;
    } else {
        result = json_dumpf(query, conn->fp, JSON_COMPACT);
        fputc('\n', conn->fp);
    }
    if (result) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                         "Timeout sending to watchman");
        } else {
            char *dump = json_dumps(query, 0);
            watchman_err(error, WATCHMAN_ERR_OTHER,
                     "Failed to send watchman query %s", dump);
            free(dump);
        }
        return 1;
    }
    return 0;
}
Пример #7
0
/*
 * Connect to watchman's socket.  Sets a socket send and receive
 * timeout of `timeout`.  Pass a {0} for no-timeout.  On error,
 * returns NULL and, if `error` is non-NULL, fills it in.
 */
struct watchman_connection *
watchman_connect(struct timeval timeout, struct watchman_error *error)
{
    struct watchman_connection *conn = NULL;
    /* If an environment variable WATCHMAN_SOCK is set, establish a connection
       to that address. Otherwise, run `watchman get-sockname` to start the
       daemon and retrieve its address. */
    const char *sockname_env = getenv("WATCHMAN_SOCK");
    if (sockname_env) {
        conn = watchman_sock_connect(sockname_env, timeout, error);
        goto done;
    }
    struct watchman_popen *p = watchman_popen_getsockname(error);
    if (p == NULL) {
        return NULL;
    }

    char buf[WATCHMAN_GET_SOCKNAME_MAX + 1];

    proto_t proto = read_with_timeout(p->fd, buf, WATCHMAN_GET_SOCKNAME_MAX, timeout);

    if (watchman_pclose(error, p)) {
        goto done;
    }
    if (proto_is_null(proto)) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got bad or no JSON/BSER from watchman get-sockname");
        goto done;
    }
    if (!proto_is_object(proto)) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got bad JSON/BSER from watchman get-sockname: object expected");
        goto bad_proto;
    }
    proto_t sockname_obj = proto_object_get(proto, "sockname");
    if (proto_is_null(sockname_obj)) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got bad JSON/BSER from watchman get-sockname: "
                     "sockname element expected");
        goto bad_proto;
    }
    if (!proto_is_string(sockname_obj)) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got bad JSON/BSER from watchman get-sockname:"
                     " sockname is not string");
        goto bad_proto;
    }
    const char *sockname = proto_strdup(sockname_obj);
    conn = watchman_sock_connect(sockname, timeout, error);
bad_proto:
    proto_free(proto);
done:
    return conn;
}
Пример #8
0
/*
 * Connect to watchman's socket.  Sets a socket send and receive
 * timeout of `timeout`.  Pass a {0} for no-timeout.  On error,
 * returns NULL and, if `error` is non-NULL, fills it in.
 */
struct watchman_connection *
watchman_connect(struct timeval timeout, struct watchman_error *error)
{
    struct watchman_connection *conn = NULL;
    /* If an environment variable WATCHMAN_SOCK is set, establish a connection
       to that address. Otherwise, run `watchman get-sockname` to start the
       daemon and retrieve its address. */
    const char *sockname_env = getenv("WATCHMAN_SOCK");
    if (sockname_env) {
        conn = watchman_sock_connect(sockname_env, timeout, error);
        goto done;
    }
    struct watchman_popen *p = watchman_popen_getsockname(error);
    if (p == NULL) {
        return NULL;
    }

    char buf[WATCHMAN_GET_SOCKNAME_MAX + 1];

    json_t *json = read_json_with_timeout(p->fd, buf, WATCHMAN_GET_SOCKNAME_MAX, timeout);

    if (watchman_pclose(error, p)) {
        goto done;
    }
    if (!json) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got bad or no JSON from watchman get-sockname");
        goto done;
    }
    if (!json_is_object(json)) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got bad JSON from watchman get-sockname: object expected");
        goto bad_json;
    }
    json_t *sockname_obj = json_object_get(json, "sockname");
    if (!sockname_obj) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got bad JSON from watchman get-sockname: "
                     "sockname element expected");
        goto bad_json;
    }
    if (!json_is_string(sockname_obj)) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Got bad JSON from watchman get-sockname:"
                     " sockname is not string");
        goto bad_json;
    }
    const char *sockname = json_string_value(sockname_obj);
    conn = watchman_sock_connect(sockname, timeout, error);
bad_json:
    json_decref(json);
done:
    return conn;
}
Пример #9
0
static struct watchman_connection *
watchman_sock_connect(const char *sockname, struct timeval timeout, struct watchman_error *error)
{
    struct sockaddr_un addr = { };

    int fd;
    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        watchman_err(error, WATCHMAN_ERR_OTHER, "Socket error %s",
                     strerror(errno));
        return NULL;
    }

    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sockname, sizeof(addr.sun_path) - 1);

    /* We don't need to worry about connect hanging, because it's a
     * Unix Domain Socket, and connect never hangs on those */
    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
        close(fd);
        watchman_err(error, WATCHMAN_ERR_CONNECT, "Connect error %s",
                     strerror(errno));
        return NULL;
    }

    if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout))) {
        watchman_err(error, WATCHMAN_ERR_CONNECT, "Failed to set timeout %s",
                     strerror(errno));
        return NULL;
    }

    if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout))) {
        watchman_err(error, WATCHMAN_ERR_CONNECT, "Failed to set timeout %s",
                     strerror(errno));
        return NULL;
    }

    FILE *sockfp = fdopen(fd, "r+");
    if (!sockfp) {
        close(fd);
        watchman_err(error, WATCHMAN_ERR_OTHER,
                     "Failed to connect to watchman socket %s: %s.",
                     sockname, strerror(errno));
        return NULL;
    }
    setlinebuf(sockfp);

    struct watchman_connection *conn = malloc(sizeof(*conn));
    conn->fp = sockfp;
    return conn;
}
Пример #10
0
static int unix_stream_connect(const char *path, struct watchman_error *error)
{
    struct sockaddr_un sa;
    struct unix_sockaddr_context ctx;

    if (unix_sockaddr_init(&sa, path, &ctx) < 0) {
        return -1;
    }
    int fd = unix_stream_socket();
    if (fd < 0) {
        return -1;
    }
    if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
        watchman_err(error, WATCHMAN_ERR_CONNECT, "Connect error %s",
                     strerror(errno));

        if (unix_sockaddr_cleanup(&ctx, error)) {
            error->code |= WATCHMAN_ERR_CWD;
        }
        close(fd);
        return -1;
    }
    if (unix_sockaddr_cleanup(&ctx, error)) {
        close(fd);
        return -1;
    }
    return fd;
}
Пример #11
0
static json_t *
watchman_read(struct watchman_connection *conn, struct watchman_error *error)
{
    json_error_t jerror;
    int flags = JSON_DISABLE_EOF_CHECK;
    json_t *result = json_loadf(conn->fp, flags, &jerror);
    if (!result) {
        watchman_err(error, "Can't parse result from watchman: %s",
                     jerror.text);
        return NULL;
    }
    if (fgetc(conn->fp) != '\n') {
        watchman_err(error, "No newline at end of reply");
        json_decref(result);
        return NULL;
    }
    return result;
}
Пример #12
0
static struct watchman_connection *
watchman_sock_connect(const char *sockname, struct timeval timeout, struct watchman_error *error)
{
    use_bser_encoding = getenv("LIBWATCHMAN_USE_JSON_PROTOCOL") == NULL;
    if (getenv("LIBWATCHMAN_TRACE_WATCHMAN") != NULL) {
            fprintf(stderr, "Using bser encoding: %s\n", use_bser_encoding ? "yes" : "no");
    }

    int fd;

    error->message = NULL;
    fd = unix_stream_connect(sockname, error);
    if (fd < 0 && !error->message) {
        watchman_err(error, WATCHMAN_ERR_CONNECT, "Connect error %s",
                     strerror(errno));
        return NULL;
    }

    if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout))) {
        watchman_err(error, WATCHMAN_ERR_CONNECT, "Failed to set timeout %s",
                     strerror(errno));
        return NULL;
    }

    if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout))) {
        watchman_err(error, WATCHMAN_ERR_CONNECT, "Failed to set timeout %s",
                     strerror(errno));
        return NULL;
    }

    FILE *sockfp = fdopen(fd, "r+");
    if (!sockfp) {
        close(fd);
        watchman_err(error, WATCHMAN_ERR_OTHER,
                     "Failed to connect to watchman socket %s: %s.",
                     sockname, strerror(errno));
        return NULL;
    }
    setlinebuf(sockfp);

    struct watchman_connection *conn = malloc(sizeof(*conn));
    conn->fp = sockfp;
    return conn;
}
Пример #13
0
struct watchman_connection *
watchman_connect(struct watchman_error *error)
{
    struct watchman_connection *conn = NULL;
    FILE *fp = popen("watchman get-sockname 2>/dev/null", "r");
    if (!fp) {
        watchman_err(error,
                     "Could not run watchman get-sockname: %s",
                     strerror(errno));
        return NULL;
    }
    json_error_t jerror;
    json_t *json = json_loadf(fp, 0, &jerror);
    pclose(fp);
    if (!json) {
        watchman_err(error,
                     "Got bad JSON from watchman get-sockname: %s",
                     jerror.text);
        goto done;
    }
    if (!json_is_object(json)) {
        watchman_err(error, "Got bad JSON from watchman get-sockname:"
                     " object expected");
        goto bad_json;
    }
    json_t *sockname_obj = json_object_get(json, "sockname");
    if (!sockname_obj) {
        watchman_err(error, "Got bad JSON from watchman get-sockname:"
                     " sockname element expected");
        goto bad_json;
    }
    if (!json_is_string(sockname_obj)) {
        watchman_err(error, "Got bad JSON from watchman get-sockname:"
                     " sockname is not string");
        goto bad_json;
    }
    const char *sockname = json_string_value(sockname_obj);
    conn = watchman_sock_connect(error, sockname);
bad_json:
    json_decref(json);
done:
    return conn;
}
Пример #14
0
static proto_t
watchman_read_with_timeout(struct watchman_connection *conn, struct timeval *timeout, struct watchman_error *error)
{
    proto_t result;
    json_error_t jerror;

    int ret = 1;

    if (!timeout || timeout->tv_sec || timeout->tv_usec)
        ret = block_on_read(fileno(conn->fp), timeout);
    if (ret == -1) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Error encountered blocking on watchman");
        return proto_null();
    }

    if (ret != 1) {
        watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                     "timed out waiting for watchman");
        return proto_null();
    }

    if (use_bser_encoding) {
        bser_t* bser = bser_parse_from_file(conn->fp, NULL);
        result = proto_from_bser(bser);
    } else {
        json_t* json = json_loadf(conn->fp, JSON_DISABLE_EOF_CHECK, &jerror);
        result = proto_from_json(json);
        if (fgetc(conn->fp) != '\n') {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                             "Timeout reading EOL from watchman");
            } else {
                watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                             "No newline at end of reply");
            }
            json_decref(json);
            return proto_null();
        }
    }
    if (proto_is_null(result)) {
        if (errno == EAGAIN) {
            watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                         "Timeout:EAGAIN reading from watchman.");
        }
        else if (errno == EWOULDBLOCK) {
            watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                         "Timeout:EWOULDBLOCK reading from watchman");
        } else {
            watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                         "Can't parse result from watchman: %s",
                         jerror.text);
        }
        return proto_null();
    }
    return result;
}
Пример #15
0
static int
watchman_send(struct watchman_connection *conn,
              json_t *query, struct watchman_error *error)
{
    int json_result = json_dumpf(query, conn->fp, JSON_COMPACT);
    if (json_result) {
        char *dump = json_dumps(query, 0);
        watchman_err(error, "Failed to send watchman query %s", dump);
        free(dump);
        return 1;
    }
    fputc('\n', conn->fp);
    return 0;
}
Пример #16
0
static int unix_sockaddr_cleanup(struct unix_sockaddr_context *ctx, struct watchman_error *error)
{
    int ret = 0;
    if (!ctx->orig_dir) {
        return 0;
    }
    /*
     * If we fail, we have moved the cwd of the whole process, which
     * could confuse calling code.  But we don't want to just die, because
     * libraries shouldn't do that.  So we'll return an error but be
     * sad about it.
     */
    if (chdir(ctx->orig_dir) < 0) {
        watchman_err(error, WATCHMAN_ERR_CWD,
                     "unable to restore original working directory");
        ret = -1;
    }
    free(ctx->orig_dir);
    return ret;
}
Пример #17
0
/* Runs watchman get-sockname and returns a FILE from which the output
 can be read. */
static struct watchman_popen *watchman_popen_getsockname(struct watchman_error *error)
{
    int pipefd[2];
    static struct watchman_popen ret = {0, 0};

    if (pipe(pipefd) < 0) {
        goto fail;
    }

    pid_t pid = fork();
    if (pid < 0) {
        goto fail;
    } else if (pid == 0) {
        if (dup2(pipefd[1], 1) < 0) {
            exit(WATCHMAN_EXEC_INTERNAL_ERROR);
        }

        int devnull_fh = open("/dev/null", O_RDWR);
        if (devnull_fh < 0) {
            exit(WATCHMAN_EXEC_INTERNAL_ERROR);
        }

        if (dup2(devnull_fh, 2) < 0) {
            exit(WATCHMAN_EXEC_INTERNAL_ERROR);
        }

        execlp("watchman", "watchman", "get-sockname", (char *) NULL);
        exit(WATCHMAN_EXEC_FAILED);
    } else {
        close(pipefd[1]);
        ret.fd = pipefd[0];
        ret.pid = pid;
        return &ret;
    }

fail:
    watchman_err(error, WATCHMAN_ERR_OTHER, get_sockname_msg, strerror(errno));
    return NULL;
}
Пример #18
0
static int
watchman_send_simple_command(struct watchman_connection *conn,
                             struct watchman_error *error, ...)
{
    int result = 0;
    json_t *cmd_array = json_array();
    va_list argptr;
    va_start(argptr, error);
    char *arg;
    while ((arg = va_arg(argptr, char *))) {
        json_array_append_new(cmd_array, json_string(arg));
    }
    int json_result = json_dumpf(cmd_array, conn->fp, JSON_COMPACT);
    if (json_result) {
        watchman_err(error, "Failed to send simple watchman command");
        result = 1;
    }
    fputc('\n', conn->fp);

    json_decref(cmd_array);
    return result;
}
Пример #19
0
static json_t *
watchman_read_with_timeout(struct watchman_connection *conn, struct timeval *timeout, struct watchman_error *error)
{
    json_error_t jerror;
    int flags = JSON_DISABLE_EOF_CHECK;
    json_t *result;

    int ret = block_on_read(fileno(conn->fp), timeout);
    if (ret == -1) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                     "Error encountered blocking on watchman");
    }

    result = json_loadf(conn->fp, flags, &jerror);
    if (!result) {
        if (errno == EAGAIN) {
            watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                         "Timeout:EAGAIN reading from watchman.");
        }
        else if (errno == EWOULDBLOCK) {
            watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                         "Timeout:EWOULDBLOCK reading from watchman");
        } else {
            watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                         "Can't parse result from watchman: %s",
                         jerror.text);
        }
        return NULL;
    }
    if (fgetc(conn->fp) != '\n') {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            watchman_err(error, WATCHMAN_ERR_TIMEOUT,
                         "Timeout reading EOL from watchman");
        } else {
            watchman_err(error, WATCHMAN_ERR_WATCHMAN_BROKEN,
                         "No newline at end of reply");
        }
        json_decref(result);
        return NULL;
    }
    return result;
}
Пример #20
0
static struct watchman_query_result *
watchman_query_json(struct watchman_connection *conn, json_t *query,
                    struct watchman_error *error)
{
    struct watchman_query_result *result = NULL;
    struct watchman_query_result *res = NULL;

    if (watchman_send(conn, query, error)) {
        return NULL;
    }
    /* parse the result */
    json_t *obj = watchman_read(conn, error);
    if (!obj) {
        return NULL;
    }
    JSON_ASSERT(json_is_object, obj, "Failed to send watchman query %s");

    json_t *jerror = json_object_get(obj, "error");
    if (jerror) {
        watchman_err(error, "Error result from watchman: %s",
                     json_string_value(jerror));
        goto done;
    }

    res = calloc(1, sizeof(*res));

    json_t *files = json_object_get(obj, "files");
    JSON_ASSERT(json_is_array, files, "Bad files %s");

    int nr = json_array_size(files);
    res->stats = calloc(nr, sizeof(*res->stats));

    int i;
    for (i = 0; i < nr; ++i) {
        struct watchman_stat *stat = res->stats + i;
        json_t *statobj = json_array_get(files, i);
        if (json_is_string(statobj)) {
            /* then hopefully we only requested names */
            stat->name = strdup(json_string_value(statobj));
            res->nr++;
            continue;
        }

        JSON_ASSERT(json_is_object, statobj, "must be object: %s");

        json_t *name = json_object_get(statobj, "name");
        JSON_ASSERT(json_is_string, name, "name must be string: %s");
        stat->name = strdup(json_string_value(name));

        WRITE_BOOL_STAT(stat, statobj, exists);
        WRITE_INT_STAT(stat, statobj, ctime);
        WRITE_INT_STAT(stat, statobj, ctime_ms);
        WRITE_INT_STAT(stat, statobj, ctime_us);
        WRITE_INT_STAT(stat, statobj, ctime_ns);
        WRITE_INT_STAT(stat, statobj, dev);
        WRITE_INT_STAT(stat, statobj, gid);
        WRITE_INT_STAT(stat, statobj, ino);
        WRITE_INT_STAT(stat, statobj, mode);
        WRITE_INT_STAT(stat, statobj, mtime);
        WRITE_INT_STAT(stat, statobj, mtime_ms);
        WRITE_INT_STAT(stat, statobj, mtime_us);
        WRITE_INT_STAT(stat, statobj, mtime_ns);
        WRITE_INT_STAT(stat, statobj, nlink);
        WRITE_INT_STAT(stat, statobj, size);
        WRITE_INT_STAT(stat, statobj, uid);

        WRITE_STR_STAT(stat, statobj, cclock);
        WRITE_STR_STAT(stat, statobj, oclock);

        WRITE_FLOAT_STAT(stat, statobj, ctime_f);
        WRITE_FLOAT_STAT(stat, statobj, mtime_f);

        /* the one we have to do manually because we don't
         * want to use the name "new" */
        json_t *newer = json_object_get(statobj, "new");
        if (newer) {
            stat->newer = json_is_true(newer);
        }
        res->nr++;
    }

    json_t *version = json_object_get(obj, "version");
    JSON_ASSERT(json_is_string, version, "Bad version %s");
    res->version = strdup(json_string_value(version));

    json_t *clock = json_object_get(obj, "clock");
    JSON_ASSERT(json_is_string, clock, "Bad clock %s");
    res->clock = strdup(json_string_value(clock));

    json_t *fresh = json_object_get(obj, "is_fresh_instance");
    JSON_ASSERT(json_is_boolean, fresh, "Bad is_fresh_instance %s");
    res->is_fresh_instance = json_is_true(fresh);

    result = res;
    res = NULL;
done:
    if (res) {
        watchman_free_query_result(res);
    }
    json_decref(obj);
    return result;
}
Пример #21
0
static struct watchman_query_result *
watchman_query_json(struct watchman_connection *conn,
                    json_t *query,
                    struct timeval *timeout,
                    struct watchman_error *error)
{
    struct watchman_query_result *result = NULL;
    struct watchman_query_result *res = NULL;

    if (watchman_send(conn, query, error)) {
        return NULL;
    }
    /* parse the result */
    proto_t obj = watchman_read_with_timeout(conn, timeout, error);
    if (proto_is_null(obj)) {
        return NULL;
    }
    PROTO_ASSERT(proto_is_object, obj, "Failed to send watchman query %s");

    proto_t jerror = proto_object_get(obj, "error");
    if (!proto_is_null(jerror)) {
        watchman_err(error, WATCHMAN_ERR_WATCHMAN_REPORTED,
                     "Error result from watchman: %s",
                     proto_strdup(jerror));
        goto done;
    }

    res = calloc(1, sizeof(*res));

    proto_t files = proto_object_get(obj, "files");
    PROTO_ASSERT(proto_is_array, files, "Bad files %s");

    int nr = proto_array_size(files);
    res->stats = calloc(nr, sizeof(*res->stats));

    int i;
    for (i = 0; i < nr; ++i) {
        struct watchman_stat *stat = res->stats + i;
        proto_t statobj = proto_array_get(files, i);
        if (proto_is_string(statobj)) {
            /* then hopefully we only requested names */
            stat->name = proto_strdup(statobj);
            res->nr++;
            continue;
        }

        PROTO_ASSERT(proto_is_object, statobj, "must be object: %s");

        proto_t name = proto_object_get(statobj, "name");
        PROTO_ASSERT(proto_is_string, name, "name must be string: %s");
        stat->name = proto_strdup(name);

        WRITE_BOOL_STAT(stat, statobj, exists);
        WRITE_INT_STAT(stat, statobj, ctime);
        WRITE_INT_STAT(stat, statobj, ctime_ms);
        WRITE_INT_STAT(stat, statobj, ctime_us);
        WRITE_INT_STAT(stat, statobj, ctime_ns);
        WRITE_INT_STAT(stat, statobj, dev);
        WRITE_INT_STAT(stat, statobj, gid);
        WRITE_INT_STAT(stat, statobj, ino);
        WRITE_INT_STAT(stat, statobj, mode);
        WRITE_INT_STAT(stat, statobj, mtime);
        WRITE_INT_STAT(stat, statobj, mtime_ms);
        WRITE_INT_STAT(stat, statobj, mtime_us);
        WRITE_INT_STAT(stat, statobj, mtime_ns);
        WRITE_INT_STAT(stat, statobj, nlink);
        WRITE_INT_STAT(stat, statobj, size);
        WRITE_INT_STAT(stat, statobj, uid);

        WRITE_STR_STAT(stat, statobj, cclock);
        WRITE_STR_STAT(stat, statobj, oclock);

        WRITE_FLOAT_STAT(stat, statobj, ctime_f);
        WRITE_FLOAT_STAT(stat, statobj, mtime_f);

        /* the one we have to do manually because we don't
         * want to use the name "new" */
        proto_t newer = proto_object_get(statobj, "new");
        if (!proto_is_null(newer)) {
            stat->newer = proto_is_true(newer);
        }
        res->nr++;
    }

    proto_t version = proto_object_get(obj, "version");
    PROTO_ASSERT(proto_is_string, version, "Bad version %s");
    res->version = proto_strdup(version);

    proto_t clock = proto_object_get(obj, "clock");
    PROTO_ASSERT(proto_is_string, clock, "Bad clock %s");
    res->clock = proto_strdup(clock);

    proto_t fresh = proto_object_get(obj, "is_fresh_instance");
    PROTO_ASSERT(proto_is_boolean, fresh, "Bad is_fresh_instance %s");
    res->is_fresh_instance = proto_is_true(fresh);

    result = res;
    res = NULL;
done:
    if (res) {
        watchman_free_query_result(res);
    }
    proto_free(obj);
    return result;
}