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 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 0 : int (*callback)() = ev->func;
240 :
241 0 : ret = poll(&ev->pfd, 1, POLL_TIME_OUT);
242 :
243 0 : if (ret <= 0) {
244 0 : if (errno == EINTR)
245 : ret = 0;
246 :
247 0 : if (ret < 0)
248 0 : pr_error("poll error: %s\n", strerror(errno));
249 :
250 0 : return ret;
251 : }
252 :
253 0 : if (ev->pfd.revents == 0)
254 : return 0;
255 :
256 0 : if (ev->pfd.events & EV_MASK_REJECTED) {
257 0 : pr_error("Error while polling. Event received: 0x%x\n", ev->pfd.events);
258 : /* We only support one event producer.
259 : * Error means that this producer died.
260 : */
261 0 : pr_error("Now closing fd and exiting.\n");
262 0 : close(ev->pfd.fd);
263 0 : ev->pfd.fd = -1;
264 : dlt_logstorage_exit();
265 0 : return -1;
266 : }
267 :
268 0 : if (!callback) {
269 0 : pr_error("Callback not found, exiting.\n");
270 : dlt_logstorage_exit();
271 0 : return -1;
272 : }
273 :
274 0 : pr_verbose("Got new event, calling %p.\n", callback);
275 :
276 0 : if (callback() < 0) {
277 0 : pr_error("Error while calling the callback, exiting.\n");
278 : dlt_logstorage_exit();
279 0 : return -1;
280 : }
281 :
282 : return 0;
283 : }
284 :
285 : /** @brief Start event loop and receive messages from DLT.
286 : *
287 : * The function will first install the signal handler,
288 : * then create the poll instance, initialize the communication controller,
289 : * initialize the event handler and finally start the polling.
290 : *
291 : * @return 0 on success, -1 on error
292 : */
293 0 : static int dlt_logstorage_ctrl_setup_event_loop(void)
294 : {
295 : int ret = 0;
296 0 : struct dlt_event ev_hdl = {
297 : .pfd = {
298 : .fd = -1,
299 : .events = POLLIN
300 : }
301 : };
302 :
303 0 : install_signal_handler();
304 :
305 0 : pr_verbose("Creating poll instance.\n");
306 :
307 : /* Initializing the communication with the daemon */
308 0 : while (dlt_control_init(analyze_response, get_ecuid(), get_verbosity()) &&
309 : !dlt_logstorage_must_exit()) {
310 0 : pr_error("Failed to initialize connection with the daemon.\n");
311 0 : pr_error("Retrying to connect in %ds.\n", get_timeout());
312 0 : sleep((unsigned int) get_timeout());
313 : }
314 :
315 0 : if (dlt_logstorage_must_exit()) {
316 0 : pr_verbose("Exiting.\n");
317 0 : return 0;
318 : }
319 :
320 0 : pr_verbose("Initializing event generator.\n");
321 :
322 0 : if (dlt_logstorage_init_handler() < 0) {
323 0 : pr_error("Failed to initialize handler.\n");
324 0 : dlt_control_deinit();
325 0 : return -1;
326 : }
327 :
328 0 : if (dlt_logstorage_ctrl_add_event(&ev_hdl,
329 : dlt_logstorage_get_handler_fd(),
330 : dlt_logstorage_get_handler_cb()) < 0) {
331 0 : pr_error("add_event error: %s\n", strerror(errno));
332 : dlt_logstorage_exit();
333 : }
334 :
335 0 : while (!dlt_logstorage_must_exit() && (ret == 0))
336 0 : ret = dlt_logstorage_ctrl_execute_event_loop(&ev_hdl);
337 :
338 : /* Clean up */
339 0 : dlt_logstorage_deinit_handler();
340 0 : dlt_control_deinit();
341 :
342 0 : return ret;
343 : }
344 :
345 : /** @brief Send a single command to DLT daemon and wait for response
346 : *
347 : * @return 0 on success, -1 otherwise.
348 : */
349 2 : static int dlt_logstorage_ctrl_single_request()
350 : {
351 : int ret = 0;
352 :
353 : /* in case sync all caches, an empty path is given */
354 2 : if (get_default_event_type() != EVENT_SYNC_CACHE) {
355 : /* Check if a 'CONF_NAME' file is present at the given path */
356 0 : if (!dlt_logstorage_check_config_file(get_default_path())) {
357 0 : pr_error("No '%s' file available at: %s\n",
358 : CONF_NAME,
359 : get_default_path());
360 0 : return -1;
361 : }
362 :
363 0 : if (!dlt_logstorage_check_directory_permission(get_default_path())) {
364 0 : pr_error("'%s' is not writable\n", get_default_path());
365 0 : return -1;
366 : }
367 : }
368 :
369 : /* Initializing the communication with the daemon */
370 2 : while (dlt_control_init(analyze_response, get_ecuid(), get_verbosity()) &&
371 : !dlt_logstorage_must_exit()) {
372 0 : pr_error("Failed to initialize connection with the daemon.\n");
373 0 : pr_error("Retrying to connect in %ds.\n", get_timeout());
374 0 : sleep( (unsigned int) get_timeout());
375 : }
376 :
377 2 : pr_verbose("event type is [%d]\t device path is [%s]\n",
378 : get_default_event_type(),
379 : get_default_path());
380 :
381 2 : ret = dlt_logstorage_send_event(get_default_event_type(),
382 : get_default_path());
383 :
384 2 : dlt_control_deinit();
385 :
386 2 : return ret;
387 : }
388 :
389 : /** @brief Print out the application help
390 : */
391 0 : static void usage(void)
392 : {
393 : printf("Usage: dlt-logstorage-ctrl [options]\n");
394 : printf("Send a trigger to DLT daemon to connect/disconnect"
395 : "a certain logstorage device\n");
396 : printf("\n");
397 : printf("Options:\n");
398 : printf(" -c --command Connection type: connect = 1, disconnect = 0\n");
399 : printf(" -d[prop] --daemonize=prop Run as daemon: prop = use proprietary handler\n");
400 : printf(" 'prop' may be replaced by any meaningful word\n");
401 : printf(" If prop is not specified, udev will be used\n");
402 : printf(" -e --ecuid Set ECU ID (Default: %s)\n", DLT_CTRL_DEFAULT_ECUID);
403 : printf(" -h --help Usage\n");
404 : printf(" -p --path Mount point path\n");
405 : printf(" -s[path] --snapshot=path Sync Logstorage cache\n");
406 : printf(" Don't use -s together with -d and -c\n");
407 : printf(" -t Specify connection timeout (Default: %ds)\n",
408 : DLT_CTRL_TIMEOUT);
409 : printf(" -S --send-header Send message with serial header (Default: Without serial header)\n");
410 : printf(" -R --resync-header Enable resync serial header\n");
411 0 : printf(" -v --verbose Set verbose flag (Default:%d)\n", get_verbosity());
412 : printf(" -C filename DLT daemon configuration file (Default: " CONFIGURATION_FILES_DIR
413 : "/dlt.conf)\n");
414 0 : }
415 :
416 : static struct option long_options[] = {
417 : {"command", required_argument, 0, 'c'},
418 : {"daemonize", optional_argument, 0, 'd'},
419 : {"ecuid", required_argument, 0, 'e'},
420 : {"help", no_argument, 0, 'h'},
421 : {"path", required_argument, 0, 'p'},
422 : {"snapshot", optional_argument, 0, 's'},
423 : {"timeout", required_argument, 0, 't'},
424 : {"send-header", no_argument, 0, 'S'},
425 : {"resync-header", no_argument, 0, 'R'},
426 : {"verbose", no_argument, 0, 'v'},
427 : {0, 0, 0, 0}
428 : };
429 :
430 : /** @brief Parses the application arguments
431 : *
432 : * The arguments are parsed and saved in static structure for future use.
433 : *
434 : * @param argc The amount of arguments
435 : * @param argv The table of arguments
436 : *
437 : * @return 0 on success, -1 otherwise
438 : */
439 2 : static int parse_args(int argc, char *argv[])
440 : {
441 : int c = -1;
442 2 : int long_index = 0;
443 :
444 6 : while ((c = getopt_long(argc,
445 : argv,
446 : ":s::t:hSRe:p:d::c:vC:",
447 : long_options,
448 6 : &long_index)) != -1)
449 4 : switch (c) {
450 2 : case 's':
451 2 : set_default_event_type(EVENT_SYNC_CACHE);
452 :
453 2 : if ((optarg != NULL) && (strlen(optarg) >= DLT_MOUNT_PATH_MAX)) {
454 0 : pr_error("Mount path '%s' too long\n", optarg);
455 0 : return -1;
456 : }
457 :
458 2 : set_default_path(optarg);
459 2 : break;
460 0 : case 't':
461 0 : if (optarg != NULL)
462 0 : set_timeout((int) strtol(optarg, NULL, 10));
463 : break;
464 0 : case 'S':
465 : {
466 0 : set_send_serial_header(1);
467 0 : break;
468 : }
469 0 : case 'R':
470 : {
471 0 : set_resync_serial_header(1);
472 0 : break;
473 : }
474 0 : case 'h':
475 0 : usage();
476 0 : return -1;
477 0 : case 'e':
478 0 : set_ecuid(optarg);
479 0 : break;
480 0 : case 'd':
481 0 : pr_verbose("Choosing handler.\n");
482 0 : set_handler_type(optarg);
483 0 : pr_verbose("Handler chosen: %d.\n", get_handler_type());
484 : break;
485 0 : case 'p':
486 :
487 0 : if ((optarg != NULL) && (strlen(optarg) >= DLT_MOUNT_PATH_MAX)) {
488 0 : pr_error("Mount path '%s' too long\n", optarg);
489 0 : return -1;
490 : }
491 :
492 0 : set_default_path(optarg);
493 0 : break;
494 0 : case 'c':
495 0 : if (optarg != NULL)
496 0 : set_default_event_type(strtol(optarg, NULL, 10));
497 : break;
498 0 : case 'v':
499 0 : set_verbosity(1);
500 0 : pr_verbose("Now in verbose mode.\n");
501 : break;
502 2 : case 'C':
503 2 : set_conf(optarg);
504 2 : pr_verbose("Set %s to read options\n", optarg);
505 : break;
506 0 : case ':':
507 0 : pr_error("Option -%c requires an argument.\n", optopt);
508 0 : usage();
509 0 : return -1;
510 0 : case '?':
511 :
512 0 : if (isprint(optopt))
513 0 : pr_error("Unknown option -%c.\n", optopt);
514 : else
515 0 : pr_error("Unknown option character \\x%x.\n", optopt);
516 :
517 0 : usage();
518 0 : return -1;
519 0 : default:
520 0 : pr_error("Try %s -h for more information.\n", argv[0]);
521 0 : return -1;
522 : }
523 :
524 :
525 :
526 4 : if ((get_default_event_type() == EVENT_SYNC_CACHE) &&
527 2 : (get_handler_type() != CTRL_NOHANDLER)) {
528 0 : pr_error("Sync caches not available in daemon mode\n");
529 0 : return -1;
530 : }
531 :
532 : /* Retrieve ECUID from dlt.conf */
533 2 : if (get_ecuid() == NULL)
534 0 : set_ecuid(NULL);
535 :
536 : return 0;
537 : }
538 :
539 : #if !defined(DLT_SYSTEMD_ENABLE)
540 0 : int sd_notify(int unset_environment, const char *state)
541 : {
542 : /* Satisfy Compiler for warnings */
543 : (void)unset_environment;
544 : (void)state;
545 0 : return 0;
546 : }
547 : #endif
548 :
549 : /** @brief Entry point
550 : *
551 : * Execute the argument parser and call the main feature accordingly.
552 : *
553 : * @param argc The amount of arguments
554 : * @param argv The table of arguments
555 : *
556 : * @return 0 on success, -1 otherwise
557 : */
558 2 : int main(int argc, char *argv[])
559 : {
560 : int ret = 0;
561 :
562 2 : set_timeout(DLT_CTRL_TIMEOUT);
563 2 : set_send_serial_header(0);
564 2 : set_resync_serial_header(0);
565 :
566 : /* Get command line arguments */
567 2 : if (parse_args(argc, argv) != 0)
568 : return -1;
569 :
570 : /* all parameter valid, start communication with daemon or setup
571 : * communication with control daemon */
572 2 : if (get_handler_type() == CTRL_NOHANDLER) {
573 2 : pr_verbose("One shot.\n");
574 :
575 2 : ret = dlt_logstorage_ctrl_single_request();
576 :
577 2 : if (ret < 0)
578 0 : pr_error("Message failed to be send. Please check DLT config.\n");
579 : }
580 : else {
581 0 : pr_verbose("Entering in daemon mode.\n");
582 :
583 : /* Let's daemonize */
584 : if (sd_notify(0, "READY=1") <= 0) {
585 0 : pr_verbose("SD notify failed, manually daemonizing.\n");
586 :
587 : /* No message can be sent or Systemd is not available.
588 : * Daemonizing manually.
589 : */
590 0 : if (daemon(1, 1)) {
591 0 : pr_error("Failed to daemonize: %s\n", strerror(errno));
592 0 : return EXIT_FAILURE;
593 : }
594 : }
595 :
596 0 : pr_verbose("Executing the event loop\n");
597 0 : ret = dlt_logstorage_ctrl_setup_event_loop();
598 : }
599 :
600 2 : pr_verbose("Exiting.\n");
601 : return ret;
602 : }
|