Line data Source code
1 : /**
2 : * Copyright (C) 2013 - 2015 Advanced Driver Information Technology.
3 : * This code is developed by Advanced Driver Information Technology.
4 : * Copyright of Advanced Driver Information Technology, Bosch and DENSO. *
5 : * This file is part of COVESA Project Dlt - Diagnostic Log and Trace console apps.
6 : *
7 : *
8 : * \copyright
9 : * This Source Code Form is subject to the terms of the
10 : * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with
11 : * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
12 : *
13 : *
14 : * \author Syed Hameed <shameed@jp.adit-jv.com> ADIT 2013 - 2015
15 : * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015
16 : * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015
17 : *
18 : * \file dlt-logstorage-ctrl.c
19 : * For further information see http://www.covesa.org/.
20 : */
21 : /*******************************************************************************
22 : ** **
23 : ** SRC-MODULE: dlt-logstorage-ctrl.c **
24 : ** **
25 : ** TARGET : linux **
26 : ** **
27 : ** PROJECT : DLT **
28 : ** **
29 : ** AUTHOR : Syed Hameed shameed@jp.adit-jv.com **
30 : ** Christoph Lipka clipka@jp.adit-jv.com **
31 : ** AnithaAmmaji.baggam@in.bosch.com **
32 : ** Frederic Berat fberat@de.adit-jv.com **
33 : ** PURPOSE : **
34 : ** **
35 : ** REMARKS : **
36 : ** **
37 : ** PLATFORM DEPENDANT [yes/no]: yes **
38 : ** **
39 : ** TO BE CHANGED BY USER [yes/no]: no **
40 : ** **
41 : *******************************************************************************/
42 :
43 : /*******************************************************************************
44 : ** Author Identity **
45 : ********************************************************************************
46 : ** Initials Name Company **
47 : ** -------- ------------------------- ---------------------------------- **
48 : ** sh Syed Hameed ADIT **
49 : ** cl Christoph Lipka ADIT **
50 : ** BA Anitha BA ADIT **
51 : ** fb Frederic Berat ADIT **
52 : *******************************************************************************/
53 :
54 : #define pr_fmt(fmt) "Logstorage control: "fmt
55 :
56 : #include <ctype.h>
57 : #include <errno.h>
58 : #include <stdio.h>
59 : #include <stdlib.h>
60 : #include <signal.h>
61 : #include <string.h>
62 : #include <getopt.h>
63 :
64 : #include <poll.h>
65 :
66 : #if defined(__linux__)
67 : # include "sd-daemon.h"
68 : #endif
69 :
70 : #include "dlt_protocol.h"
71 : #include "dlt_client.h"
72 : #include "dlt-control-common.h"
73 : #include "dlt-logstorage-common.h"
74 : #include "dlt-logstorage-ctrl.h"
75 :
76 : #define POLL_TIME_OUT 500
77 : #define EV_MASK_REJECTED (POLLERR | POLLHUP | POLLNVAL)
78 :
79 : #define DLT_LOGSTORAGE_CTRL_EXIT 1
80 : static int must_exit;
81 : struct dlt_event {
82 : struct pollfd pfd;
83 : void *func;
84 : };
85 :
86 : /** @brief Triggers the application exit
87 : *
88 : * The application will exit on next poll timeout.
89 : */
90 0 : void dlt_logstorage_exit(void)
91 : {
92 0 : must_exit = DLT_LOGSTORAGE_CTRL_EXIT;
93 0 : }
94 :
95 : /** @brief Check if the application must exit
96 : *
97 : * The application will exit on next poll timeout.
98 : */
99 0 : int dlt_logstorage_must_exit(void)
100 : {
101 0 : return must_exit;
102 : }
103 :
104 : /** @brief Signal handler.
105 : *
106 : * Triggers the exit of the application in case of specific signals
107 : *
108 : * @param signo The value of the signal received.
109 : */
110 0 : static void catch_signal(int signo)
111 : {
112 0 : if (signo) {
113 0 : pr_error("Signal %d received, exiting.", signo);
114 : dlt_logstorage_exit();
115 : }
116 0 : }
117 :
118 : /** @brief Install a handler for some signals
119 : *
120 : * Handler are installed on exit related signals. That allows one to exit from
121 : * the main loop gracefully.
122 : */
123 0 : static void install_signal_handler(void)
124 : {
125 0 : int signals[] = { SIGINT, SIGQUIT, SIGTERM, 0 };
126 : unsigned int i;
127 : struct sigaction sa;
128 :
129 0 : pr_verbose("Installing signal handler.\n");
130 :
131 : /* install a signal handler for the above listed signals */
132 0 : for (i = 0; signals[i]; i++) {
133 : memset(&sa, 0, sizeof(sa));
134 0 : sa.sa_handler = catch_signal;
135 :
136 0 : if (sigaction(signals[i], &sa, NULL) < 0)
137 0 : pr_error("Failed to install signal %u handler. Error: %s\n",
138 : signals[i], strerror(errno));
139 : }
140 0 : }
141 :
142 : #define MAX_RESPONSE_LENGTH 32
143 : /** @brief Analyze the daemon answer to a request
144 : *
145 : * This function checks whether if the daemon answered positively to
146 : * the request or not.
147 : *
148 : * @param data The textual answer
149 : * @param payload The answer payload
150 : * @param len The answer payload length
151 : * @return 0 on success, -1 otherwise.
152 : */
153 2 : static int analyze_response(char *data, void *payload, int len)
154 : {
155 : int ret = -1;
156 2 : char resp_ok[MAX_RESPONSE_LENGTH] = { 0 };
157 2 : char resp_warning[MAX_RESPONSE_LENGTH] = { 0 };
158 2 : char resp_perm_denied[MAX_RESPONSE_LENGTH] = { 0 };
159 :
160 2 : if ((data == NULL) || (payload == NULL))
161 : return -1;
162 :
163 : /* satisfy compiler */
164 : (void)payload;
165 : (void)len;
166 :
167 : snprintf(resp_ok,
168 : MAX_RESPONSE_LENGTH,
169 : "service(%d), ok",
170 : DLT_SERVICE_ID_OFFLINE_LOGSTORAGE);
171 :
172 : snprintf(resp_warning,
173 : MAX_RESPONSE_LENGTH,
174 : "service(%d), warning",
175 : DLT_SERVICE_ID_OFFLINE_LOGSTORAGE);
176 :
177 : snprintf(resp_perm_denied,
178 : MAX_RESPONSE_LENGTH,
179 : "service(%d), perm_denied",
180 : DLT_SERVICE_ID_OFFLINE_LOGSTORAGE);
181 :
182 2 : if (strncmp(data, resp_ok, strlen(resp_ok)) == 0)
183 : ret = 0;
184 :
185 2 : if (strncmp(data, resp_warning, strlen(resp_warning)) == 0) {
186 0 : pr_error("Warning:Some filter configurations are ignored due to configuration issues \n");
187 : ret = 0;
188 : }
189 :
190 2 : if (strncmp(data, resp_perm_denied, strlen(resp_perm_denied)) == 0) {
191 0 : pr_error("Warning: Permission denied.\n");
192 : ret = 0;
193 : }
194 :
195 2 : pr_verbose("Response received: '%s'\n", data);
196 2 : pr_verbose("Response expected: '%s'\n", resp_ok);
197 :
198 : return ret;
199 : }
200 :
201 : /** @brief Add a new event to watch
202 : *
203 : * This function could be exported to be used by udev/prop so that they can
204 : * register several events.
205 : *
206 : * @param ev_hdl The structure containing the file descriptors
207 : * @param fd The file descriptor to watch
208 : * @param cb The callback to be called on event.
209 : *
210 : * @return 0 on success, -1 if the parameters are invalid.
211 : */
212 0 : static int dlt_logstorage_ctrl_add_event(struct dlt_event *ev_hdl,
213 : int fd,
214 : void *cb)
215 : {
216 0 : if ((fd < 0) || !cb || !ev_hdl) {
217 0 : pr_error("Wrong parameter to add event (%d %p)\n", fd, cb);
218 0 : return -1;
219 : }
220 :
221 0 : pr_verbose("Setting up the event handler with (%d, %p).\n", fd, cb);
222 :
223 0 : ev_hdl->func = cb;
224 0 : ev_hdl->pfd.fd = fd;
225 :
226 0 : return 0;
227 : }
228 :
229 : /** @brief Main execution loop
230 : *
231 : * Waits on events, and executes the callbacks retrieved
232 : * back from the event structure.
233 : *
234 : * @return 0 on success, -1 otherwise.
235 : */
236 0 : static int dlt_logstorage_ctrl_execute_event_loop(struct dlt_event *ev)
237 : {
238 : int ret = 0;
239 : union {
240 : void *ptr;
241 : int (*callback)(void);
242 : } callback_converter;
243 : int (*callback)(void);
244 :
245 0 : callback_converter.ptr = ev->func;
246 0 : callback = callback_converter.callback;
247 :
248 0 : ret = poll(&ev->pfd, 1, POLL_TIME_OUT);
249 :
250 0 : if (ret <= 0) {
251 0 : if (errno == EINTR)
252 : ret = 0;
253 :
254 0 : if (ret < 0)
255 0 : pr_error("poll error: %s\n", strerror(errno));
256 :
257 0 : return ret;
258 : }
259 :
260 0 : if (ev->pfd.revents == 0)
261 : return 0;
262 :
263 0 : if (ev->pfd.events & EV_MASK_REJECTED) {
264 0 : pr_error("Error while polling. Event received: 0x%x\n", ev->pfd.events);
265 : /* We only support one event producer.
266 : * Error means that this producer died.
267 : */
268 0 : pr_error("Now closing fd and exiting.\n");
269 0 : close(ev->pfd.fd);
270 0 : ev->pfd.fd = -1;
271 : dlt_logstorage_exit();
272 0 : return -1;
273 : }
274 :
275 0 : if (!callback) {
276 0 : pr_error("Callback not found, exiting.\n");
277 : dlt_logstorage_exit();
278 0 : return -1;
279 : }
280 :
281 : callback_converter.callback = callback;
282 0 : pr_verbose("Got new event, calling %p.\n", callback_converter.ptr);
283 :
284 0 : if (callback() < 0) {
285 0 : pr_error("Error while calling the callback, exiting.\n");
286 : dlt_logstorage_exit();
287 0 : return -1;
288 : }
289 :
290 : return 0;
291 : }
292 :
293 : /** @brief Start event loop and receive messages from DLT.
294 : *
295 : * The function will first install the signal handler,
296 : * then create the poll instance, initialize the communication controller,
297 : * initialize the event handler and finally start the polling.
298 : *
299 : * @return 0 on success, -1 on error
300 : */
301 0 : static int dlt_logstorage_ctrl_setup_event_loop(void)
302 : {
303 : int ret = 0;
304 0 : struct dlt_event ev_hdl = {
305 : .pfd = {
306 : .fd = -1,
307 : .events = POLLIN
308 : }
309 : };
310 :
311 0 : install_signal_handler();
312 :
313 0 : pr_verbose("Creating poll instance.\n");
314 :
315 : /* Initializing the communication with the daemon */
316 0 : while (dlt_control_init(analyze_response, get_ecuid(), get_verbosity()) &&
317 : !dlt_logstorage_must_exit()) {
318 0 : pr_error("Failed to initialize connection with the daemon.\n");
319 0 : pr_error("Retrying to connect in %ds.\n", get_timeout());
320 0 : sleep((unsigned int) get_timeout());
321 : }
322 :
323 0 : if (dlt_logstorage_must_exit()) {
324 0 : pr_verbose("Exiting.\n");
325 0 : return 0;
326 : }
327 :
328 0 : pr_verbose("Initializing event generator.\n");
329 :
330 0 : if (dlt_logstorage_init_handler() < 0) {
331 0 : pr_error("Failed to initialize handler.\n");
332 0 : dlt_control_deinit();
333 0 : return -1;
334 : }
335 :
336 0 : if (dlt_logstorage_ctrl_add_event(&ev_hdl,
337 : dlt_logstorage_get_handler_fd(),
338 : dlt_logstorage_get_handler_cb()) < 0) {
339 0 : pr_error("add_event error: %s\n", strerror(errno));
340 : dlt_logstorage_exit();
341 : }
342 :
343 0 : while (!dlt_logstorage_must_exit() && (ret == 0))
344 0 : ret = dlt_logstorage_ctrl_execute_event_loop(&ev_hdl);
345 :
346 : /* Clean up */
347 0 : dlt_logstorage_deinit_handler();
348 0 : dlt_control_deinit();
349 :
350 0 : return ret;
351 : }
352 :
353 : /** @brief Send a single command to DLT daemon and wait for response
354 : *
355 : * @return 0 on success, -1 otherwise.
356 : */
357 2 : static int dlt_logstorage_ctrl_single_request()
358 : {
359 : int ret = 0;
360 :
361 : /* in case sync all caches, an empty path is given */
362 2 : if (get_default_event_type() != EVENT_SYNC_CACHE) {
363 : /* Check if a 'CONF_NAME' file is present at the given path */
364 0 : if (!dlt_logstorage_check_config_file(get_default_path())) {
365 0 : pr_error("No '%s' file available at: %s\n",
366 : CONF_NAME,
367 : get_default_path());
368 0 : return -1;
369 : }
370 :
371 0 : if (!dlt_logstorage_check_directory_permission(get_default_path())) {
372 0 : pr_error("'%s' is not writable\n", get_default_path());
373 0 : return -1;
374 : }
375 : }
376 :
377 : /* Initializing the communication with the daemon */
378 2 : while (dlt_control_init(analyze_response, get_ecuid(), get_verbosity()) &&
379 : !dlt_logstorage_must_exit()) {
380 0 : pr_error("Failed to initialize connection with the daemon.\n");
381 0 : pr_error("Retrying to connect in %ds.\n", get_timeout());
382 0 : sleep( (unsigned int) get_timeout());
383 : }
384 :
385 2 : pr_verbose("event type is [%d]\t device path is [%s]\n",
386 : get_default_event_type(),
387 : get_default_path());
388 :
389 2 : ret = dlt_logstorage_send_event(get_default_event_type(),
390 : get_default_path());
391 :
392 2 : dlt_control_deinit();
393 :
394 2 : return ret;
395 : }
396 :
397 : /** @brief Print out the application help
398 : */
399 0 : static void usage(void)
400 : {
401 : printf("Usage: dlt-logstorage-ctrl [options]\n");
402 : printf("Send a trigger to DLT daemon to connect/disconnect"
403 : "a certain logstorage device\n");
404 : printf("\n");
405 : printf("Options:\n");
406 : printf(" -c --command Connection type: connect = 1, disconnect = 0\n");
407 : printf(" -d[prop] --daemonize=prop Run as daemon: prop = use proprietary handler\n");
408 : printf(" 'prop' may be replaced by any meaningful word\n");
409 : printf(" If prop is not specified, udev will be used\n");
410 : printf(" -e --ecuid Set ECU ID (Default: %s)\n", DLT_CTRL_DEFAULT_ECUID);
411 : printf(" -h --help Usage\n");
412 : printf(" -p --path Mount point path\n");
413 : printf(" -s[path] --snapshot=path Sync Logstorage cache\n");
414 : printf(" Don't use -s together with -d and -c\n");
415 : printf(" -t Specify connection timeout (Default: %ds)\n",
416 : DLT_CTRL_TIMEOUT);
417 : printf(" -S --send-header Send message with serial header (Default: Without serial header)\n");
418 : printf(" -R --resync-header Enable resync serial header\n");
419 0 : printf(" -v --verbose Set verbose flag (Default:%d)\n", get_verbosity());
420 : printf(" -C filename DLT daemon configuration file (Default: " CONFIGURATION_FILES_DIR
421 : "/dlt.conf)\n");
422 0 : }
423 :
424 : static struct option long_options[] = {
425 : {"command", required_argument, 0, 'c'},
426 : {"daemonize", optional_argument, 0, 'd'},
427 : {"ecuid", required_argument, 0, 'e'},
428 : {"help", no_argument, 0, 'h'},
429 : {"path", required_argument, 0, 'p'},
430 : {"snapshot", optional_argument, 0, 's'},
431 : {"timeout", required_argument, 0, 't'},
432 : {"send-header", no_argument, 0, 'S'},
433 : {"resync-header", no_argument, 0, 'R'},
434 : {"verbose", no_argument, 0, 'v'},
435 : {0, 0, 0, 0}
436 : };
437 :
438 : /** @brief Parses the application arguments
439 : *
440 : * The arguments are parsed and saved in static structure for future use.
441 : *
442 : * @param argc The amount of arguments
443 : * @param argv The table of arguments
444 : *
445 : * @return 0 on success, -1 otherwise
446 : */
447 2 : static int parse_args(int argc, char *argv[])
448 : {
449 : int c = -1;
450 2 : int long_index = 0;
451 :
452 6 : while ((c = getopt_long(argc,
453 : argv,
454 : ":s::t:hSRe:p:d::c:vC:",
455 : long_options,
456 6 : &long_index)) != -1)
457 4 : switch (c) {
458 2 : case 's':
459 2 : set_default_event_type(EVENT_SYNC_CACHE);
460 :
461 2 : if ((optarg != NULL) && (strlen(optarg) >= DLT_MOUNT_PATH_MAX)) {
462 0 : pr_error("Mount path '%s' too long\n", optarg);
463 0 : return -1;
464 : }
465 :
466 2 : set_default_path(optarg);
467 2 : break;
468 0 : case 't':
469 0 : if (optarg != NULL)
470 0 : set_timeout((int) strtol(optarg, NULL, 10));
471 : break;
472 0 : case 'S':
473 : {
474 0 : set_send_serial_header(1);
475 0 : break;
476 : }
477 0 : case 'R':
478 : {
479 0 : set_resync_serial_header(1);
480 0 : break;
481 : }
482 0 : case 'h':
483 0 : usage();
484 0 : return -1;
485 0 : case 'e':
486 0 : set_ecuid(optarg);
487 0 : break;
488 0 : case 'd':
489 0 : pr_verbose("Choosing handler.\n");
490 0 : set_handler_type(optarg);
491 0 : pr_verbose("Handler chosen: %d.\n", get_handler_type());
492 : break;
493 0 : case 'p':
494 :
495 0 : if ((optarg != NULL) && (strlen(optarg) >= DLT_MOUNT_PATH_MAX)) {
496 0 : pr_error("Mount path '%s' too long\n", optarg);
497 0 : return -1;
498 : }
499 :
500 0 : set_default_path(optarg);
501 0 : break;
502 0 : case 'c':
503 0 : if (optarg != NULL)
504 0 : set_default_event_type(strtol(optarg, NULL, 10));
505 : break;
506 0 : case 'v':
507 0 : set_verbosity(1);
508 0 : pr_verbose("Now in verbose mode.\n");
509 : break;
510 2 : case 'C':
511 2 : set_conf(optarg);
512 2 : pr_verbose("Set %s to read options\n", optarg);
513 : break;
514 0 : case ':':
515 0 : pr_error("Option -%c requires an argument.\n", optopt);
516 0 : usage();
517 0 : return -1;
518 0 : case '?':
519 :
520 0 : if (isprint(optopt))
521 0 : pr_error("Unknown option -%c.\n", optopt);
522 : else
523 0 : pr_error("Unknown option character \\x%x.\n", optopt);
524 :
525 0 : usage();
526 0 : return -1;
527 0 : default:
528 0 : pr_error("Try %s -h for more information.\n", argv[0]);
529 0 : return -1;
530 : }
531 :
532 :
533 :
534 4 : if ((get_default_event_type() == EVENT_SYNC_CACHE) &&
535 2 : (get_handler_type() != CTRL_NOHANDLER)) {
536 0 : pr_error("Sync caches not available in daemon mode\n");
537 0 : return -1;
538 : }
539 :
540 : /* Retrieve ECUID from dlt.conf */
541 2 : if (get_ecuid() == NULL)
542 0 : set_ecuid(NULL);
543 :
544 : return 0;
545 : }
546 :
547 : #if !defined(DLT_SYSTEMD_ENABLE)
548 0 : int sd_notify(int unset_environment, const char *state)
549 : {
550 : /* Satisfy Compiler for warnings */
551 : (void)unset_environment;
552 : (void)state;
553 0 : return 0;
554 : }
555 : #endif
556 :
557 : /** @brief Entry point
558 : *
559 : * Execute the argument parser and call the main feature accordingly.
560 : *
561 : * @param argc The amount of arguments
562 : * @param argv The table of arguments
563 : *
564 : * @return 0 on success, -1 otherwise
565 : */
566 2 : int main(int argc, char *argv[])
567 : {
568 : int ret = 0;
569 :
570 2 : set_timeout(DLT_CTRL_TIMEOUT);
571 2 : set_send_serial_header(0);
572 2 : set_resync_serial_header(0);
573 :
574 : /* Get command line arguments */
575 2 : if (parse_args(argc, argv) != 0)
576 : return -1;
577 :
578 : /* all parameter valid, start communication with daemon or setup
579 : * communication with control daemon */
580 2 : if (get_handler_type() == CTRL_NOHANDLER) {
581 2 : pr_verbose("One shot.\n");
582 :
583 2 : ret = dlt_logstorage_ctrl_single_request();
584 :
585 2 : if (ret < 0)
586 0 : pr_error("Message failed to be send. Please check DLT config.\n");
587 : }
588 : else {
589 0 : pr_verbose("Entering in daemon mode.\n");
590 :
591 : /* Let's daemonize */
592 : if (sd_notify(0, "READY=1") <= 0) {
593 0 : pr_verbose("SD notify failed, manually daemonizing.\n");
594 :
595 : /* No message can be sent or Systemd is not available.
596 : * Daemonizing manually.
597 : */
598 0 : if (daemon(1, 1)) {
599 0 : pr_error("Failed to daemonize: %s\n", strerror(errno));
600 0 : return EXIT_FAILURE;
601 : }
602 : }
603 :
604 0 : pr_verbose("Executing the event loop\n");
605 0 : ret = dlt_logstorage_ctrl_setup_event_loop();
606 : }
607 :
608 2 : pr_verbose("Exiting.\n");
609 : return ret;
610 : }
|