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; }
int watchman_version(struct watchman_connection *conn, struct watchman_error *error, struct watchman_version* version) { const char *result = NULL; json_t *cmd = json_array(); json_array_append_new(cmd, json_string("version")); int ret = watchman_send(conn, cmd, error); json_decref(cmd); if (ret) { return -1; } proto_t obj = watchman_read(conn, error); if (proto_is_null(obj)) { return -1; } PROTO_ASSERT(proto_is_object, obj, "Got bogus value from version %s"); proto_t version_field = proto_object_get(obj, "version"); PROTO_ASSERT(proto_is_string, version_field, "Bad version %s"); result = proto_strdup(version_field); int count = sscanf(result, "%d.%d.%d", &version->major, &version->minor, &version->micro); proto_free(obj); return count == 3 ? 0 : -1; done: proto_free(obj); return -1; }
char * watchman_clock(struct watchman_connection *conn, const char *path, unsigned int sync_timeout, struct watchman_error *error) { char *result = NULL; json_t *query = json_array(); json_array_append_new(query, json_string("clock")); json_array_append_new(query, json_string(path)); if (sync_timeout) { json_t *options = json_object(); json_object_set_new(options, "sync_timeout", json_integer(sync_timeout)); json_array_append_new(query, options); } int ret = watchman_send(conn, query, error); json_decref(query); if (ret) { return NULL; } proto_t obj = watchman_read(conn, error); if (proto_is_null(obj)) { return NULL; } PROTO_ASSERT(proto_is_object, obj, "Got bogus value from clock %s"); proto_t clock = proto_object_get(obj, "clock"); PROTO_ASSERT(proto_is_string, clock, "Bad clock %s"); result = proto_strdup(clock); done: proto_free(obj); return result; }
/* * 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; }
/* Release a reference to SA. */ void sa_release(struct sa *sa) { struct cert_handler *handler; struct proto *proto; LOG_DBG((LOG_SA, 80, "sa_release: SA %p had %d references", sa, sa->refcnt)); if (--sa->refcnt) return; LOG_DBG((LOG_SA, 60, "sa_release: freeing SA %p", sa)); while ((proto = TAILQ_FIRST(&sa->protos)) != 0) proto_free(proto); if (sa->data) { if (sa->doi && sa->doi->free_sa_data) sa->doi->free_sa_data(sa->data); free(sa->data); } free(sa->id_i); free(sa->id_r); if (sa->recv_cert) { handler = cert_get(sa->recv_certtype); if (handler) handler->cert_free(sa->recv_cert); } if (sa->sent_cert) { handler = cert_get(sa->sent_certtype); if (handler) handler->cert_free(sa->sent_cert); } if (sa->recv_key) key_free(sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, sa->recv_key); free(sa->keynote_key); /* This is just a string */ if (sa->policy_id != -1) kn_close(sa->policy_id); free(sa->name); free(sa->keystate); if (sa->nat_t_keepalive) timer_remove_event(sa->nat_t_keepalive); if (sa->dpd_event) timer_remove_event(sa->dpd_event); if (sa->transport) transport_release(sa->transport); free(sa->tag); free(sa); }
struct watchman_watch_list * watchman_watch_list(struct watchman_connection *conn, struct watchman_error *error) { struct watchman_watch_list *res = NULL; struct watchman_watch_list *result = NULL; if (watchman_send_simple_command(conn, error, "watch-list", NULL)) { return NULL; } proto_t obj = watchman_read(conn, error); if (proto_is_null(obj)) { return NULL; } PROTO_ASSERT(proto_is_object, obj, "Got bogus value from watch-list %s"); proto_t roots = proto_object_get(obj, "roots"); PROTO_ASSERT(proto_is_array, roots, "Got bogus value from watch-list %s"); res = malloc(sizeof(*res)); int nr = proto_array_size(roots); res->nr = 0; res->roots = calloc(nr, sizeof(*res->roots)); int i; for (i = 0; i < nr; ++i) { proto_t root = proto_array_get(roots, i); PROTO_ASSERT(proto_is_string, root, "Got non-string root from watch-list %s"); res->nr++; res->roots[i] = proto_strdup(root); } result = res; res = NULL; done: if (res) { watchman_free_watch_list(res); } proto_free(obj); return result; }
int watchman_shutdown_server(struct watchman_connection *conn, struct watchman_error *error) { json_t *cmd = json_array(); json_array_append_new(cmd, json_string("shutdown-server")); int ret = watchman_send(conn, cmd, error); json_decref(cmd); if (ret) { return -1; } proto_t obj = watchman_read(conn, error); if (proto_is_null(obj)) { return -1; } proto_free(obj); return 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; }