parser.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "parser.h"
  3. static inline int find_keyword(char *str, char *keyword, int max_size, int (*custom_isspace)(char))
  4. {
  5. char *s = str, *keyword_start;
  6. while (unlikely(custom_isspace(*s))) s++;
  7. keyword_start = s;
  8. while (likely(*s && !custom_isspace(*s)) && max_size > 1) {
  9. *keyword++ = *s++;
  10. max_size--;
  11. }
  12. *keyword = '\0';
  13. return max_size == 0 ? 0 : (int) (s - keyword_start);
  14. }
  15. /*
  16. * Initialize a parser
  17. * user : as defined by the user, will be shared across calls
  18. * input : main input stream (auto detect stream -- file, socket, pipe)
  19. * buffer : This is the buffer to be used (if null a buffer of size will be allocated)
  20. * size : buffer size either passed or will be allocated
  21. * If the buffer is auto allocated, it will auto freed when the parser is destroyed
  22. *
  23. *
  24. */
  25. PARSER *parser_init(RRDHOST *host, void *user, void *input, PARSER_INPUT_TYPE flags)
  26. {
  27. PARSER *parser;
  28. parser = callocz(1, sizeof(*parser));
  29. parser->plugins_action = callocz(1, sizeof(PLUGINSD_ACTION));
  30. parser->user = user;
  31. parser->input = input;
  32. parser->flags = flags;
  33. parser->host = host;
  34. #ifdef ENABLE_HTTPS
  35. parser->bytesleft = 0;
  36. parser->readfrom = NULL;
  37. #endif
  38. if (unlikely(!(flags & PARSER_NO_PARSE_INIT))) {
  39. parser_add_keyword(parser, PLUGINSD_KEYWORD_FLUSH, pluginsd_flush);
  40. parser_add_keyword(parser, PLUGINSD_KEYWORD_CHART, pluginsd_chart);
  41. parser_add_keyword(parser, PLUGINSD_KEYWORD_DIMENSION, pluginsd_dimension);
  42. parser_add_keyword(parser, PLUGINSD_KEYWORD_DISABLE, pluginsd_disable);
  43. parser_add_keyword(parser, PLUGINSD_KEYWORD_VARIABLE, pluginsd_variable);
  44. parser_add_keyword(parser, PLUGINSD_KEYWORD_LABEL, pluginsd_label);
  45. parser_add_keyword(parser, PLUGINSD_KEYWORD_OVERWRITE, pluginsd_overwrite);
  46. parser_add_keyword(parser, PLUGINSD_KEYWORD_END, pluginsd_end);
  47. parser_add_keyword(parser, "CLABEL_COMMIT", pluginsd_clabel_commit);
  48. parser_add_keyword(parser, "CLABEL", pluginsd_clabel);
  49. parser_add_keyword(parser, PLUGINSD_KEYWORD_BEGIN, pluginsd_begin);
  50. parser_add_keyword(parser, "SET", pluginsd_set);
  51. }
  52. return parser;
  53. }
  54. /*
  55. * Push a new line into the parsing stream
  56. *
  57. * This line will be the next one to process ie the next fetch will get this one
  58. *
  59. */
  60. int parser_push(PARSER *parser, char *line)
  61. {
  62. PARSER_DATA *tmp_parser_data;
  63. if (unlikely(!parser))
  64. return 1;
  65. if (unlikely(!line))
  66. return 0;
  67. tmp_parser_data = callocz(1, sizeof(*tmp_parser_data));
  68. tmp_parser_data->line = strdupz(line);
  69. tmp_parser_data->next = parser->data;
  70. parser->data = tmp_parser_data;
  71. return 0;
  72. }
  73. /*
  74. * Add a keyword and the corresponding function that will be called
  75. * Multiple functions may be added
  76. * Input : keyword
  77. * : callback function
  78. * : flags
  79. * Output: > 0 registered function number
  80. * : 0 Error
  81. */
  82. int parser_add_keyword(PARSER *parser, char *keyword, keyword_function func)
  83. {
  84. PARSER_KEYWORD *tmp_keyword;
  85. if (strcmp(keyword, "_read") == 0) {
  86. parser->read_function = (void *) func;
  87. return 0;
  88. }
  89. if (strcmp(keyword, "_eof") == 0) {
  90. parser->eof_function = (void *) func;
  91. return 0;
  92. }
  93. if (strcmp(keyword, "_unknown") == 0) {
  94. parser->unknown_function = (void *) func;
  95. return 0;
  96. }
  97. uint32_t keyword_hash = simple_hash(keyword);
  98. tmp_keyword = parser->keyword;
  99. while (tmp_keyword) {
  100. if (tmp_keyword->keyword_hash == keyword_hash && (!strcmp(tmp_keyword->keyword, keyword))) {
  101. if (tmp_keyword->func_no == PARSER_MAX_CALLBACKS)
  102. return 0;
  103. tmp_keyword->func[tmp_keyword->func_no++] = (void *) func;
  104. return tmp_keyword->func_no;
  105. }
  106. tmp_keyword = tmp_keyword->next;
  107. }
  108. tmp_keyword = callocz(1, sizeof(*tmp_keyword));
  109. tmp_keyword->worker_job_id = parser->worker_job_ids++;
  110. tmp_keyword->keyword = strdupz(keyword);
  111. tmp_keyword->keyword_hash = keyword_hash;
  112. tmp_keyword->func[tmp_keyword->func_no++] = (void *) func;
  113. worker_register_job_name(tmp_keyword->worker_job_id, tmp_keyword->keyword);
  114. tmp_keyword->next = parser->keyword;
  115. parser->keyword = tmp_keyword;
  116. return tmp_keyword->func_no;
  117. }
  118. /*
  119. * Cleanup a previously allocated parser
  120. */
  121. void parser_destroy(PARSER *parser)
  122. {
  123. if (unlikely(!parser))
  124. return;
  125. PARSER_KEYWORD *tmp_keyword, *tmp_keyword_next;
  126. PARSER_DATA *tmp_parser_data, *tmp_parser_data_next;
  127. // Remove keywords
  128. tmp_keyword = parser->keyword;
  129. while (tmp_keyword) {
  130. tmp_keyword_next = tmp_keyword->next;
  131. freez(tmp_keyword->keyword);
  132. freez(tmp_keyword);
  133. tmp_keyword = tmp_keyword_next;
  134. }
  135. // Remove pushed data if any
  136. tmp_parser_data = parser->data;
  137. while (tmp_parser_data) {
  138. tmp_parser_data_next = tmp_parser_data->next;
  139. freez(tmp_parser_data->line);
  140. freez(tmp_parser_data);
  141. tmp_parser_data = tmp_parser_data_next;
  142. }
  143. freez(parser->plugins_action);
  144. freez(parser);
  145. }
  146. /*
  147. * Fetch the next line to process
  148. *
  149. */
  150. int parser_next(PARSER *parser)
  151. {
  152. char *tmp = NULL;
  153. if (unlikely(!parser))
  154. return 1;
  155. parser->flags &= ~(PARSER_INPUT_PROCESSED);
  156. PARSER_DATA *tmp_parser_data = parser->data;
  157. if (unlikely(tmp_parser_data)) {
  158. strncpyz(parser->buffer, tmp_parser_data->line, PLUGINSD_LINE_MAX);
  159. parser->data = tmp_parser_data->next;
  160. freez(tmp_parser_data->line);
  161. freez(tmp_parser_data);
  162. return 0;
  163. }
  164. if (unlikely(parser->read_function))
  165. tmp = parser->read_function(parser->buffer, PLUGINSD_LINE_MAX, parser->input);
  166. else
  167. tmp = fgets(parser->buffer, PLUGINSD_LINE_MAX, (FILE *)parser->input);
  168. if (unlikely(!tmp)) {
  169. if (unlikely(parser->eof_function)) {
  170. int rc = parser->eof_function(parser->input);
  171. error("read failed: user defined function returned %d", rc);
  172. }
  173. else {
  174. if (feof((FILE *)parser->input))
  175. error("read failed: end of file");
  176. else if (ferror((FILE *)parser->input))
  177. error("read failed: input error");
  178. else
  179. error("read failed: unknown error");
  180. }
  181. return 1;
  182. }
  183. return 0;
  184. }
  185. /*
  186. * Takes an initialized parser object that has an unprocessed entry (by calling parser_next)
  187. * and if it contains a valid keyword, it will execute all the callbacks
  188. *
  189. */
  190. inline int parser_action(PARSER *parser, char *input)
  191. {
  192. PARSER_RC rc = PARSER_RC_OK;
  193. char *words[PLUGINSD_MAX_WORDS] = { NULL };
  194. char command[PLUGINSD_LINE_MAX + 1];
  195. keyword_function action_function;
  196. keyword_function *action_function_list = NULL;
  197. if (unlikely(!parser))
  198. return 1;
  199. parser->recover_location[0] = 0x0;
  200. // if not direct input check if we have reprocessed this
  201. if (unlikely(!input && parser->flags & PARSER_INPUT_PROCESSED))
  202. return 0;
  203. PARSER_KEYWORD *tmp_keyword = parser->keyword;
  204. if (unlikely(!tmp_keyword)) {
  205. return 1;
  206. }
  207. if (unlikely(!input))
  208. input = parser->buffer;
  209. if (unlikely(!find_keyword(input, command, PLUGINSD_LINE_MAX, pluginsd_space)))
  210. return 0;
  211. if ((parser->flags & PARSER_INPUT_ORIGINAL) == PARSER_INPUT_ORIGINAL)
  212. pluginsd_split_words(input, words, PLUGINSD_MAX_WORDS, parser->recover_input, parser->recover_location, PARSER_MAX_RECOVER_KEYWORDS);
  213. else
  214. pluginsd_split_words(input, words, PLUGINSD_MAX_WORDS, NULL, NULL, 0);
  215. uint32_t command_hash = simple_hash(command);
  216. size_t worker_job_id = 0;
  217. while(tmp_keyword) {
  218. if (command_hash == tmp_keyword->keyword_hash &&
  219. (!strcmp(command, tmp_keyword->keyword))) {
  220. action_function_list = &tmp_keyword->func[0];
  221. worker_job_id = tmp_keyword->worker_job_id;
  222. break;
  223. }
  224. tmp_keyword = tmp_keyword->next;
  225. }
  226. if (unlikely(!action_function_list)) {
  227. if (unlikely(parser->unknown_function))
  228. rc = parser->unknown_function(words, parser->user, NULL);
  229. else
  230. rc = PARSER_RC_ERROR;
  231. #ifdef NETDATA_INTERNAL_CHECKS
  232. error("Unknown keyword [%s]", input);
  233. #endif
  234. }
  235. else {
  236. worker_is_busy(worker_job_id);
  237. while ((action_function = *action_function_list) != NULL) {
  238. rc = action_function(words, parser->user, parser->plugins_action);
  239. if (unlikely(rc == PARSER_RC_ERROR || rc == PARSER_RC_STOP))
  240. break;
  241. action_function_list++;
  242. }
  243. worker_is_idle();
  244. }
  245. if (likely(input == parser->buffer))
  246. parser->flags |= PARSER_INPUT_PROCESSED;
  247. return (rc == PARSER_RC_ERROR);
  248. }
  249. inline int parser_recover_input(PARSER *parser)
  250. {
  251. if (unlikely(!parser))
  252. return 1;
  253. for(int i=0; i < PARSER_MAX_RECOVER_KEYWORDS && parser->recover_location[i]; i++)
  254. *(parser->recover_location[i]) = parser->recover_input[i];
  255. parser->recover_location[0] = 0x0;
  256. return 0;
  257. }