bool w_query_legacy_field_list(struct w_query_field_list *flist) { static const char *names[] = { "name", "exists", "size", "mode", "uid", "gid", "mtime", "ctime", "ino", "dev", "nlink", "new", "cclock", "oclock" }; uint8_t i; json_t *list = json_array(); bool res; char *errmsg = NULL; for (i = 0; i < sizeof(names)/sizeof(names[0]); i++) { json_array_append_new(list, json_string_nocheck(names[i])); } res = parse_field_list(list, flist, &errmsg); json_decref(list); if (errmsg) { w_log(W_LOG_FATAL, "should never happen: %s\n", errmsg); } return res; }
void w_query_legacy_field_list(w_query_field_list* flist) { static const char *names[] = { "name", "exists", "size", "mode", "uid", "gid", "mtime", "ctime", "ino", "dev", "nlink", "new", "cclock", "oclock" }; uint8_t i; auto list = json_array(); for (i = 0; i < sizeof(names)/sizeof(names[0]); i++) { json_array_append_new(list, typed_string_to_json(names[i], W_STRING_UNICODE)); } parse_field_list(list, flist); }
std::shared_ptr<w_query> w_query_parse( const std::shared_ptr<w_root_t>& root, const json_ref& query) { auto result = std::make_shared<w_query>(); auto res = result.get(); parse_benchmark(res, query); parse_case_sensitive(res, root, query); parse_sync(res, query); parse_dedup(res, query); parse_lock_timeout(res, query); parse_relative_root(root, res, query); parse_empty_on_fresh_instance(res, query); /* Look for path generators */ parse_paths(res, query); /* Look for glob generators */ parse_globs(res, query); /* Look for suffix generators */ parse_suffixes(res, query); /* Look for since generator */ parse_since(res, query); parse_query_expression(res, query); parse_request_id(res, query); parse_field_list(query.get_default("fields"), &res->fieldList); res->query_spec = query; return result; }
/* subscribe /root subname {query} * Subscribes the client connection to the specified root. */ void cmd_subscribe(struct watchman_client *client, json_t *args) { w_root_t *root; struct watchman_client_subscription *sub; json_t *resp; const char *name; json_t *jfield_list; w_query *query; json_t *query_spec; struct w_query_field_list field_list; char *errmsg; if (json_array_size(args) != 4) { send_error_response(client, "wrong number of arguments for subscribe"); return; } root = resolve_root_or_err(client, args, 1, true); if (!root) { return; } name = json_string_value(json_array_get(args, 2)); if (!name) { send_error_response(client, "expected 2nd parameter to be subscription name"); goto done; } query_spec = json_array_get(args, 3); jfield_list = json_object_get(query_spec, "fields"); if (!parse_field_list(jfield_list, &field_list, &errmsg)) { send_error_response(client, "invalid field list: %s", errmsg); free(errmsg); goto done; } query = w_query_parse(query_spec, &errmsg); if (!query) { send_error_response(client, "failed to parse query: %s", errmsg); free(errmsg); goto done; } sub = calloc(1, sizeof(*sub)); if (!sub) { send_error_response(client, "no memory!"); goto done; } sub->name = w_string_new(name); sub->query = query; memcpy(&sub->field_list, &field_list, sizeof(field_list)); sub->root = root; pthread_mutex_lock(&w_client_lock); w_ht_replace(client->subscriptions, w_ht_ptr_val(sub->name), w_ht_ptr_val(sub)); pthread_mutex_unlock(&w_client_lock); resp = make_response(); annotate_with_clock(root, resp); set_prop(resp, "subscribe", json_string(name)); send_and_dispose_response(client, resp); resp = build_subscription_results(sub, root); if (resp) { send_and_dispose_response(client, resp); } done: w_root_delref(root); }
/* query /root {query} */ static void cmd_query(struct watchman_client *client, json_t *args) { w_root_t *root; w_query *query; json_t *query_spec; char *errmsg = NULL; w_query_res res; json_t *response; json_t *file_list, *jfield_list; char clockbuf[128]; struct w_query_field_list field_list; if (json_array_size(args) != 3) { send_error_response(client, "wrong number of arguments for 'query'"); return; } root = resolve_root_or_err(client, args, 1, false); if (!root) { return; } query_spec = json_array_get(args, 2); jfield_list = json_object_get(query_spec, "fields"); if (!parse_field_list(jfield_list, &field_list, &errmsg)) { send_error_response(client, "invalid field list: %s", errmsg); free(errmsg); w_root_delref(root); return; } query = w_query_parse(root, query_spec, &errmsg); if (!query) { send_error_response(client, "failed to parse query: %s", errmsg); free(errmsg); w_root_delref(root); return; } if (client->client_mode) { query->sync_timeout = 0; } if (!w_query_execute(query, root, &res, NULL, NULL)) { send_error_response(client, "query failed: %s", res.errmsg); w_query_result_free(&res); w_root_delref(root); w_query_delref(query); return; } w_query_delref(query); file_list = w_query_results_to_json(&field_list, res.num_results, res.results); w_query_result_free(&res); response = make_response(); if (clock_id_string(res.root_number, res.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "clock", json_string_nocheck(clockbuf)); } set_prop(response, "is_fresh_instance", json_pack("b", res.is_fresh_instance)); set_prop(response, "files", file_list); send_and_dispose_response(client, response); w_root_delref(root); }
struct watchman_trigger_command *w_build_trigger_from_def( w_root_t *root, json_t *trig, char **errmsg) { struct watchman_trigger_command *cmd; json_t *ele, *query; json_int_t jint; const char *name = NULL; cmd = calloc(1, sizeof(*cmd)); if (!cmd) { *errmsg = strdup("no memory"); return NULL; } cmd->definition = trig; json_incref(cmd->definition); query = json_pack("{s:O}", "expression", json_object_get(cmd->definition, "expression")); cmd->query = w_query_parse(query, errmsg); json_decref(query); if (!cmd->query) { w_trigger_command_free(cmd); return NULL; } json_unpack(trig, "{s:s}", "name", &name); if (!name) { *errmsg = strdup("invalid or missing name"); w_trigger_command_free(cmd); return NULL; } cmd->triggername = w_string_new(name); cmd->command = json_object_get(trig, "command"); if (cmd->command) { json_incref(cmd->command); } if (!cmd->command || !json_is_array(cmd->command) || !json_array_size(cmd->command)) { *errmsg = strdup("invalid command array"); w_trigger_command_free(cmd); return NULL; } json_unpack(trig, "{s:b}", "append_files", &cmd->append_files); ele = json_object_get(trig, "stdin"); if (!ele) { cmd->stdin_style = input_dev_null; } else if (json_is_array(ele)) { cmd->stdin_style = input_json; if (!parse_field_list(ele, &cmd->field_list, errmsg)) { w_trigger_command_free(cmd); return NULL; } } else if (json_is_string(ele)) { const char *str = json_string_value(ele); if (!strcmp(str, "/dev/null")) { cmd->stdin_style = input_dev_null; } else if (!strcmp(str, "NAME_PER_LINE")) { cmd->stdin_style = input_name_list; } else { ignore_result(asprintf(errmsg, "invalid stdin value %s", str)); w_trigger_command_free(cmd); return NULL; } } else { *errmsg = strdup("invalid value for stdin"); w_trigger_command_free(cmd); return NULL; } jint = 0; // unlimited unless specified json_unpack(trig, "{s:I}", "max_files_stdin", &jint); if (jint < 0) { *errmsg = strdup("max_files_stdin must be >= 0"); w_trigger_command_free(cmd); return NULL; } cmd->max_files_stdin = jint; json_unpack(trig, "{s:s}", "stdout", &cmd->stdout_name); json_unpack(trig, "{s:s}", "stderr", &cmd->stderr_name); if (!parse_redirection(&cmd->stdout_name, &cmd->stdout_flags, "stdout", errmsg)) { w_trigger_command_free(cmd); return NULL; } if (!parse_redirection(&cmd->stderr_name, &cmd->stderr_flags, "stderr", errmsg)) { w_trigger_command_free(cmd); return NULL; } // Copy current environment cmd->envht = w_envp_make_ht(); // Set some standard vars w_envp_set(cmd->envht, "WATCHMAN_ROOT", root->root_path); w_envp_set_cstring(cmd->envht, "WATCHMAN_SOCK", get_sock_name()); w_envp_set(cmd->envht, "WATCHMAN_TRIGGER", cmd->triggername); return cmd; }
/* subscribe /root subname {query} * Subscribes the client connection to the specified root. */ static void cmd_subscribe(struct watchman_client *client, json_t *args) { w_root_t *root; struct watchman_client_subscription *sub; json_t *resp; const char *name; json_t *jfield_list; w_query *query; json_t *query_spec; struct w_query_field_list field_list; char *errmsg; int defer = true; /* can't use bool because json_unpack requires int */ json_t *defer_list = NULL; json_t *drop_list = NULL; if (json_array_size(args) != 4) { send_error_response(client, "wrong number of arguments for subscribe"); return; } root = resolve_root_or_err(client, args, 1, true); if (!root) { return; } name = json_string_value(json_array_get(args, 2)); if (!name) { send_error_response(client, "expected 2nd parameter to be subscription name"); goto done; } query_spec = json_array_get(args, 3); jfield_list = json_object_get(query_spec, "fields"); if (!parse_field_list(jfield_list, &field_list, &errmsg)) { send_error_response(client, "invalid field list: %s", errmsg); free(errmsg); goto done; } query = w_query_parse(root, query_spec, &errmsg); if (!query) { send_error_response(client, "failed to parse query: %s", errmsg); free(errmsg); goto done; } json_unpack(query_spec, "{s?:o}", "defer", &defer_list); if (defer_list && !json_is_array(defer_list)) { send_error_response(client, "defer field must be an array of strings"); goto done; } json_unpack(query_spec, "{s?:o}", "drop", &drop_list); if (drop_list && !json_is_array(drop_list)) { send_error_response(client, "drop field must be an array of strings"); goto done; } sub = calloc(1, sizeof(*sub)); if (!sub) { send_error_response(client, "no memory!"); goto done; } sub->name = w_string_new(name); sub->query = query; json_unpack(query_spec, "{s?:b}", "defer_vcs", &defer); sub->vcs_defer = defer; if (drop_list || defer_list) { size_t i; sub->drop_or_defer = w_ht_new(2, &w_ht_string_funcs); if (defer_list) { for (i = 0; i < json_array_size(defer_list); i++) { w_ht_replace(sub->drop_or_defer, w_ht_ptr_val(w_string_new(json_string_value( json_array_get(defer_list, i)))), false); } } if (drop_list) { for (i = 0; i < json_array_size(drop_list); i++) { w_ht_replace(sub->drop_or_defer, w_ht_ptr_val(w_string_new(json_string_value( json_array_get(drop_list, i)))), true); } } } memcpy(&sub->field_list, &field_list, sizeof(field_list)); sub->root = root; pthread_mutex_lock(&w_client_lock); w_ht_replace(client->subscriptions, w_ht_ptr_val(sub->name), w_ht_ptr_val(sub)); pthread_mutex_unlock(&w_client_lock); resp = make_response(); annotate_with_clock(root, resp); set_prop(resp, "subscribe", json_string(name)); add_root_warnings_to_response(resp, root); send_and_dispose_response(client, resp); resp = build_subscription_results(sub, root); if (resp) { send_and_dispose_response(client, resp); } done: w_root_delref(root); }