4
0

qdevice-heuristics-worker-cmd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * Copyright (c) 2015-2017 Red Hat, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Jan Friesse (jfriesse@redhat.com)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the Red Hat, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <stdio.h>
  37. #include "dynar.h"
  38. #include "dynar-str.h"
  39. #include "qdevice-heuristics-io.h"
  40. #include "qdevice-heuristics-worker.h"
  41. #include "qdevice-heuristics-worker-cmd.h"
  42. #include "qdevice-heuristics-cmd-str.h"
  43. #include "qdevice-heuristics-worker-log.h"
  44. static int
  45. qdevice_heuristics_worker_cmd_process_exec_list_add(struct qdevice_heuristics_worker_instance *instance,
  46. struct dynar *data)
  47. {
  48. size_t zi;
  49. char *exec_name;
  50. char *exec_command;
  51. char *str;
  52. str = dynar_data(data);
  53. /*
  54. * Skip to first space
  55. */
  56. for (zi = 0; str[zi] != ' ' && str[zi] != '\0'; zi++) ;
  57. if (str[zi] == '\0') {
  58. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  59. "qdevice_heuristics_worker_cmd_process_exec_list_add: Can't find first space");
  60. return (-1);
  61. }
  62. /*
  63. * Skip to the end of spaces
  64. */
  65. for (; str[zi] == ' '; zi++) ;
  66. if (str[zi] == '\0') {
  67. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  68. "qdevice_heuristics_worker_cmd_process_exec_list_add: Can't find start of exec name");
  69. return (-1);
  70. }
  71. /*
  72. * Found exec name
  73. */
  74. exec_name = str + zi;
  75. /*
  76. * Skip to the next spaces
  77. */
  78. for (; str[zi] != ' ' && str[zi] != '\0'; zi++) ;
  79. if (str[zi] == '\0') {
  80. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  81. "qdevice_heuristics_worker_cmd_process_exec_list_add: Can't find second space");
  82. return (-1);
  83. }
  84. /*
  85. * Put trailing \0 into exec_name
  86. */
  87. str[zi] = '\0';
  88. zi++;
  89. /*
  90. * Skip to the end of next spaces
  91. */
  92. for (; str[zi] == ' '; zi++) ;
  93. if (str[zi] == '\0') {
  94. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  95. "qdevice_heuristics_worker_cmd_process_exec_list_add: Can't find start of exec command");
  96. return (-1);
  97. }
  98. /*
  99. * Found exec_command
  100. */
  101. exec_command = str + zi;
  102. qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
  103. "qdevice_heuristics_worker_cmd_process_one_line: Received exec-list-add command "
  104. "with name \"%s\" and command \"%s\"", exec_name, exec_command);
  105. if (qdevice_heuristics_exec_list_add(&instance->exec_list, exec_name, exec_command) == NULL) {
  106. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  107. "qdevice_heuristics_worker_cmd_process_exec_list_add: Can't alloc exec list entry");
  108. return (-1);
  109. }
  110. return (0);
  111. }
  112. static int
  113. qdevice_heuristics_worker_cmd_process_exec(struct qdevice_heuristics_worker_instance *instance,
  114. struct dynar *data)
  115. {
  116. uint32_t timeout;
  117. uint32_t seq_number;
  118. char *str;
  119. struct qdevice_heuristics_exec_list_entry *exec_list_entry;
  120. struct process_list_entry *plist_entry;
  121. str = dynar_data(data);
  122. if (sscanf(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_ADD_SPACE "%"PRIu32" %"PRIu32, &timeout,
  123. &seq_number) != 2) {
  124. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  125. "qdevice_heuristics_worker_cmd_process_exec: Can't parse command (sscanf)");
  126. return (-1);
  127. }
  128. qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
  129. "qdevice_heuristics_worker_cmd_process_exec: Received exec command "
  130. "with seq_no \"%"PRIu32"\" and timeout \"%"PRIu32"\"", seq_number, timeout);
  131. if (instance->exec_timeout_timer != NULL) {
  132. process_list_move_active_entries_to_kill_list(&instance->main_process_list);
  133. timer_list_delete(&instance->main_timer_list, instance->exec_timeout_timer);
  134. instance->exec_timeout_timer = NULL;
  135. }
  136. instance->last_exec_seq_number = seq_number;
  137. if (qdevice_heuristics_exec_list_is_empty(&instance->exec_list)) {
  138. if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
  139. instance->last_exec_seq_number,
  140. QDEVICE_HEURISTICS_EXEC_RESULT_DISABLED) != 0) {
  141. return (-1);
  142. }
  143. } else {
  144. /*
  145. * Initialize process list (from exec list)
  146. */
  147. TAILQ_FOREACH(exec_list_entry, &instance->exec_list, entries) {
  148. plist_entry = process_list_add(&instance->main_process_list,
  149. exec_list_entry->name, exec_list_entry->command);
  150. if (plist_entry == NULL) {
  151. qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
  152. "qdevice_heuristics_worker_cmd_process_exec: Can't allocate "
  153. "process list entry");
  154. process_list_move_active_entries_to_kill_list(
  155. &instance->main_process_list);
  156. if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
  157. instance->last_exec_seq_number,
  158. QDEVICE_HEURISTICS_EXEC_RESULT_FAIL) != 0) {
  159. return (-1);
  160. }
  161. return (0);
  162. }
  163. }
  164. if (process_list_exec_initialized(&instance->main_process_list) != 0) {
  165. qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
  166. "qdevice_heuristics_worker_cmd_process_exec: Can't execute "
  167. "process list");
  168. process_list_move_active_entries_to_kill_list(&instance->main_process_list);
  169. if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
  170. instance->last_exec_seq_number,
  171. QDEVICE_HEURISTICS_EXEC_RESULT_FAIL) != 0) {
  172. return (-1);
  173. }
  174. return (0);
  175. }
  176. instance->exec_timeout_timer = timer_list_add(&instance->main_timer_list,
  177. timeout, qdevice_heuristics_worker_exec_timeout_timer_callback,
  178. (void *)instance, NULL);
  179. if (instance->exec_timeout_timer == NULL) {
  180. qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
  181. "qdevice_heuristics_worker_cmd_process_exec: Can't add exec timeout "
  182. "timer to timer list");
  183. process_list_move_active_entries_to_kill_list(&instance->main_process_list);
  184. if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
  185. instance->last_exec_seq_number,
  186. QDEVICE_HEURISTICS_EXEC_RESULT_FAIL) != 0) {
  187. return (-1);
  188. }
  189. return (0);
  190. }
  191. }
  192. return (0);
  193. }
  194. /*
  195. * 1 - Line processed
  196. * 0 - No line to process - everything processed
  197. * -1 - Error
  198. */
  199. static int
  200. qdevice_heuristics_worker_cmd_process_one_line(struct qdevice_heuristics_worker_instance *instance,
  201. struct dynar *data)
  202. {
  203. char *str;
  204. size_t str_len;
  205. size_t nl_pos;
  206. size_t zi;
  207. str = dynar_data(data);
  208. str_len = dynar_size(data);
  209. /*
  210. * Find valid line
  211. */
  212. for (zi = 0; zi < str_len && str[zi] != '\r' && str[zi] != '\n'; zi++) ;
  213. if (zi >= str_len) {
  214. /*
  215. * Command is not yet fully readed
  216. */
  217. return (0);
  218. }
  219. nl_pos = zi;
  220. str[nl_pos] = '\0';
  221. if (strcmp(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_CLEAR) == 0) {
  222. qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
  223. "qdevice_heuristics_worker_cmd_process_one_line: Received exec-list-clear command");
  224. qdevice_heuristics_exec_list_free(&instance->exec_list);
  225. } else if (strncmp(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_ADD_SPACE,
  226. strlen(QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_ADD)) == 0) {
  227. if (qdevice_heuristics_worker_cmd_process_exec_list_add(instance, data) != 0) {
  228. return (-1);
  229. }
  230. } else if (strncmp(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_ADD_SPACE,
  231. strlen(QDEVICE_HEURISTICS_CMD_STR_EXEC_ADD_SPACE)) == 0) {
  232. if (qdevice_heuristics_worker_cmd_process_exec(instance, data) != 0) {
  233. return (-1);
  234. }
  235. } else {
  236. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  237. "qdevice_heuristics_worker_cmd_process_one_line: Unknown command \"%s\" "
  238. "received from main qdevice process", str);
  239. return (-1);
  240. }
  241. /*
  242. * Find place where is begining of new "valid" line
  243. */
  244. for (zi = nl_pos + 1; zi < str_len && (str[zi] == '\0' || str[zi] == '\n' || str[zi] == '\r'); zi++) ;
  245. memmove(str, str + zi, str_len - zi);
  246. if (dynar_set_size(data, str_len - zi) == -1) {
  247. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  248. "qdevice_heuristics_worker_cmd_process_one_line: Can't set dynar size");
  249. return (-1);
  250. }
  251. return (1);
  252. }
  253. /*
  254. * 0 - No error
  255. * -1 - Error
  256. */
  257. static int
  258. qdevice_heuristics_worker_cmd_process(struct qdevice_heuristics_worker_instance *instance)
  259. {
  260. int res;
  261. while ((res =
  262. qdevice_heuristics_worker_cmd_process_one_line(instance, &instance->cmd_in_buffer)) == 1) ;
  263. return (res);
  264. }
  265. /*
  266. * 0 - No error
  267. * 1 - Error
  268. */
  269. int
  270. qdevice_heuristics_worker_cmd_read_from_pipe(struct qdevice_heuristics_worker_instance *instance)
  271. {
  272. int res;
  273. int ret;
  274. res = qdevice_heuristics_io_read(QDEVICE_HEURISTICS_WORKER_CMD_IN_FD, &instance->cmd_in_buffer);
  275. ret = 0;
  276. switch (res) {
  277. case 0:
  278. /*
  279. * Partial read
  280. */
  281. break;
  282. case -1:
  283. qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
  284. "Lost connection with main qdevice process");
  285. ret = -1;
  286. break;
  287. case -2:
  288. qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
  289. "Heuristics sent too long command line");
  290. ret = -1;
  291. break;
  292. case -3:
  293. qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
  294. "Unhandled error when reading from heuristics command in fd");
  295. ret = -1;
  296. break;
  297. case 1:
  298. /*
  299. * At least one log line received
  300. */
  301. ret = qdevice_heuristics_worker_cmd_process(instance);
  302. break;
  303. }
  304. return (ret);
  305. }
  306. int
  307. qdevice_heuristics_worker_cmd_write_exec_result(struct qdevice_heuristics_worker_instance *instance,
  308. uint32_t seq_number, enum qdevice_heuristics_exec_result exec_result)
  309. {
  310. if (dynar_str_cpy(&instance->cmd_out_buffer,
  311. QDEVICE_HEURISTICS_CMD_STR_EXEC_RESULT_ADD_SPACE) != -1 &&
  312. dynar_str_catf(&instance->cmd_out_buffer, "%"PRIu32" %u\n", seq_number,
  313. (int)exec_result) != -1) {
  314. (void)qdevice_heuristics_io_blocking_write(QDEVICE_HEURISTICS_WORKER_CMD_OUT_FD,
  315. dynar_data(&instance->cmd_out_buffer), dynar_size(&instance->cmd_out_buffer));
  316. } else {
  317. qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
  318. "Can't alloc memory for exec result");
  319. return (-1);
  320. }
  321. return (0);
  322. }