automotive-dlt
dlt-receive.c
Go to the documentation of this file.
1 /*
2  * @licence app begin@
3  * SPDX license identifier: MPL-2.0
4  *
5  * Copyright (C) 2011-2015, BMW AG
6  *
7  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
8  *
9  * This Source Code Form is subject to the terms of the
10  * Mozilla Public License (MPL), v. 2.0.
11  * If a copy of the MPL was not distributed with this file,
12  * You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * For further information see http://www.genivi.org/.
15  * @licence end@
16  */
17 
28 /*******************************************************************************
29 ** **
30 ** SRC-MODULE: dlt-receive.cpp **
31 ** **
32 ** TARGET : linux **
33 ** **
34 ** PROJECT : DLT **
35 ** **
36 ** AUTHOR : Alexander Wenzel Alexander.AW.Wenzel@bmw.de **
37 ** Markus Klein **
38 ** **
39 ** PURPOSE : **
40 ** **
41 ** REMARKS : **
42 ** **
43 ** PLATFORM DEPENDANT [yes/no]: yes **
44 ** **
45 ** TO BE CHANGED BY USER [yes/no]: no **
46 ** **
47 *******************************************************************************/
48 
49 /*******************************************************************************
50 ** Author Identity **
51 ********************************************************************************
52 ** **
53 ** Initials Name Company **
54 ** -------- ------------------------- ---------------------------------- **
55 ** aw Alexander Wenzel BMW **
56 ** mk Markus Klein Fraunhofer ESK **
57 *******************************************************************************/
58 
59 /*******************************************************************************
60 ** Revision Control History **
61 *******************************************************************************/
62 
63 /*
64  * $LastChangedRevision: 1670 $
65  * $LastChangedDate: 2011-04-08 15:12:06 +0200 (Fr, 08. Apr 2011) $
66  * $LastChangedBy$
67  Initials Date Comment
68  aw 13.01.2010 initial
69  */
70 
71 #include <ctype.h> /* for isprint() */
72 #include <stdlib.h> /* for atoi() */
73 #include <sys/stat.h> /* for S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH */
74 #include <fcntl.h> /* for open() */
75 #include <sys/uio.h> /* for writev() */
76 #include <errno.h>
77 #include <string.h>
78 #include <glob.h>
79 #include <syslog.h>
80 #include <linux/limits.h> /* for PATH_MAX */
81 #include <inttypes.h>
82 
83 #include "dlt_client.h"
84 
85 #define DLT_RECEIVE_TEXTBUFSIZE 10024 /* Size of buffer for text output */
86 
87 #define DLT_RECEIVE_ECU_ID "RECV"
88 
89 /* Function prototypes */
90 int dlt_receive_message_callback(DltMessage *message, void *data);
91 
92 typedef struct {
93  int aflag;
94  int sflag;
95  int xflag;
96  int mflag;
97  int vflag;
98  int yflag;
99  char *ovalue;
100  char *ovaluebase; /* ovalue without ".dlt" */
101  char *fvalue;
102  char *evalue;
103  int bvalue;
104  int64_t climit;
105  char ecuid[4];
106  int ohandle;
107  int64_t totalbytes; /* bytes written so far into the output file, used to check the file size limit */
108  int part_num; /* number of current output file if limit was exceeded */
109  DltFile file;
110  DltFilter filter;
112 
116 void usage()
117 {
118  char version[255];
119 
120  dlt_get_version(version,255);
121 
122  printf("Usage: dlt-receive [options] hostname/serial_device_name\n");
123  printf("Receive DLT messages from DLT daemon and print or store the messages.\n");
124  printf("Use filters to filter received messages.\n");
125  printf("%s \n", version);
126  printf("Options:\n");
127  printf(" -a Print DLT messages; payload as ASCII\n");
128  printf(" -x Print DLT messages; payload as hex\n");
129  printf(" -m Print DLT messages; payload as hex and ASCII\n");
130  printf(" -s Print DLT messages; only headers\n");
131  printf(" -v Verbose mode\n");
132  printf(" -h Usage\n");
133  printf(" -y Serial device mode\n");
134  printf(" -b baudrate Serial device baudrate (Default: 115200)\n");
135  printf(" -e ecuid Set ECU ID (Default: RECV)\n");
136  printf(" -o filename Output messages in new DLT file\n");
137  printf(" -c limit Restrict file size to <limit> bytes when output to file\n");
138  printf(" When limit is reached, a new file is opened. Use K,M,G as\n");
139  printf(" suffix to specify kilo-, mega-, giga-bytes respectively\n");
140  printf(" -f filename Enable filtering of messages\n");
141 }
142 
143 
144 int64_t convert_arg_to_byte_size(char * arg)
145 {
146  size_t i;
147  int64_t factor;
148  int64_t result;
149  /* check if valid input */
150  for (i = 0; i<strlen(arg)-1; ++i)
151  {
152  if (!isdigit(arg[i]))
153  {
154  return -2;
155  }
156  }
157 
158  /* last character */
159  factor = 1;
160  if ((arg[strlen(arg)-1] == 'K') || (arg[strlen(arg)-1] == 'k'))
161  {
162  factor = 1024;
163  }
164  else if ((arg[strlen(arg)-1] == 'M') || (arg[strlen(arg)-1] == 'm'))
165  {
166  factor = 1024 * 1024;
167  }
168  else if ((arg[strlen(arg)-1] == 'G') || (arg[strlen(arg)-1] == 'g'))
169  {
170  factor = 1024 * 1024 * 1024;
171  }
172  else
173  {
174  if (!isdigit(arg[strlen(arg)-1]))
175  {
176  return -2;
177  }
178  }
179 
180  /* range checking */
181  int64_t const mult = atoll(arg);
182  if (((INT64_MAX)/factor) < mult)
183  {
184  /* Would overflow! */
185  return -2;
186  }
187 
188  result = factor * mult;
189 
190  /* The result be at least the size of one message
191  * One message consists of its header + user data:
192  */
193  DltMessage msg;
194  int64_t min_size = sizeof(msg.headerbuffer);
195  min_size += 2048 /* DLT_USER_BUF_MAX_SIZE */;
196 
197  if (min_size > result)
198  {
199  char tmp[256];
200  snprintf(tmp, 256, "ERROR: Specified limit: %" PRId64 "is smaller than a the size of a single message: %" PRId64 "!\n", result, min_size);
201  dlt_log(LOG_ERR, tmp);
202  result = -2;
203  }
204 
205  return result;
206 }
207 
208 
209 /*
210  * open output file
211  */
213 {
214  /* if (file_already_exists) */
215  glob_t outer;
216  if (glob(dltdata->ovalue, GLOB_TILDE_CHECK | GLOB_NOSORT, NULL, &outer) == 0)
217  {
218  if (dltdata->vflag)
219  {
220  char tmp[256];
221  snprintf(tmp, 256, "File %s already exists, need to rename first\n", dltdata->ovalue);
222  dlt_log(LOG_INFO, tmp);
223  }
224 
225  if (dltdata->part_num < 0)
226  {
227  char pattern[PATH_MAX+1];
228  pattern[PATH_MAX] = 0;
229  snprintf(pattern, PATH_MAX, "%s.*.dlt", dltdata->ovaluebase);
230  glob_t inner;
231 
232  /* sort does not help here because we have to traverse the
233  * full result in any case. Remember, a sorted list would look like:
234  * foo.1.dlt
235  * foo.10.dlt
236  * foo.1000.dlt
237  * foo.11.dlt
238  */
239  if (glob(pattern, GLOB_TILDE_CHECK | GLOB_NOSORT, NULL, &inner) == 0)
240  {
241  /* search for the highest number used */
242  size_t i;
243  for (i= 0; i<inner.gl_pathc; ++i)
244  {
245  /* convert string that follows the period after the initial portion,
246  * e.g. gt.gl_pathv[i] = foo.1.dlt -> atoi("1.dlt");
247  */
248  int cur = atoi(&inner.gl_pathv[i][strlen(dltdata->ovaluebase)+1]);
249  if (cur > dltdata->part_num)
250  {
251  dltdata->part_num = cur;
252  }
253  }
254  }
255  globfree(&inner);
256 
257  ++dltdata->part_num;
258 
259  }
260 
261  char filename[PATH_MAX+1];
262  filename[PATH_MAX] = 0;
263 
264  snprintf(filename, PATH_MAX, "%s.%i.dlt", dltdata->ovaluebase, dltdata->part_num++);
265  if (rename(dltdata->ovalue, filename) != 0)
266  {
267  char tmp[256];
268  snprintf(tmp, 256, "ERROR: rename %s to %s failed with error %s\n", dltdata->ovalue, filename, strerror(errno));
269  dlt_log(LOG_ERR, tmp);
270  }
271  else
272  {
273  if (dltdata->vflag)
274  {
275  char tmp[256];
276  snprintf(tmp, 256, "Renaming existing file from %s to %s\n", dltdata->ovalue, filename);
277  dlt_log(LOG_INFO, tmp);
278  }
279  }
280 
281  } /* if (file_already_exists) */
282  globfree(&outer);
283 
284  dltdata->ohandle = open(dltdata->ovalue, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
285  return dltdata->ohandle;
286 }
287 
288 
290 {
291  if (dltdata->ohandle)
292  {
293  close(dltdata->ohandle);
294  dltdata->ohandle = -1;
295  }
296 }
297 
298 
302 int main(int argc, char* argv[])
303 {
304  DltClient dltclient;
305  DltReceiveData dltdata;
306  int c;
307  int index;
308 
309  /* Initialize dltdata */
310  dltdata.aflag = 0;
311  dltdata.sflag = 0;
312  dltdata.xflag = 0;
313  dltdata.mflag = 0;
314  dltdata.vflag = 0;
315  dltdata.yflag = 0;
316  dltdata.ovalue = 0;
317  dltdata.ovaluebase = 0;
318  dltdata.fvalue = 0;
319  dltdata.evalue = 0;
320  dltdata.bvalue = 0;
321  dltdata.climit = -1; /* default: -1 = unlimited */
322  dltdata.ohandle=-1;
323  dltdata.totalbytes = 0;
324  dltdata.part_num = -1;
325 
326  /* Fetch command line arguments */
327  opterr = 0;
328 
329  while ((c = getopt (argc, argv, "vashyxmf:o:e:b:c:")) != -1)
330  switch (c)
331  {
332  case 'v':
333  {
334  dltdata.vflag = 1;
335  break;
336  }
337  case 'a':
338  {
339  dltdata.aflag = 1;
340  break;
341  }
342  case 's':
343  {
344  dltdata.sflag = 1;
345  break;
346  }
347  case 'x':
348  {
349  dltdata.xflag = 1;
350  break;
351  }
352  case 'm':
353  {
354  dltdata.mflag = 1;
355  break;
356  }
357  case 'h':
358  {
359  usage();
360  return -1;
361  }
362  case 'y':
363  {
364  dltdata.yflag = 1;
365  break;
366  }
367  case 'f':
368  {
369  dltdata.fvalue = optarg;
370  break;
371  }
372  case 'o':
373  {
374  dltdata.ovalue = optarg;
375  size_t to_copy = strlen(dltdata.ovalue);
376  if (strcmp(&dltdata.ovalue[to_copy-4], ".dlt") == 0)
377  {
378  to_copy = to_copy - 4;
379  }
380 
381  dltdata.ovaluebase = strndup(dltdata.ovalue, to_copy);
382  break;
383  }
384  case 'e':
385  {
386  dltdata.evalue = optarg;
387  break;
388  }
389  case 'b':
390  {
391  dltdata.bvalue = atoi(optarg);
392  break;
393  }
394 
395  case 'c':
396  {
397  dltdata.climit = convert_arg_to_byte_size(optarg);
398  if (dltdata.climit < -1)
399  {
400  fprintf (stderr, "Invalid argument for option -c.\n");
401  /* unknown or wrong option used, show usage information and terminate */
402  usage();
403  return -1;
404  }
405  break;
406  }
407  case '?':
408  {
409  if (optopt == 'o' || optopt == 'f' || optopt == 'c')
410  {
411  fprintf (stderr, "Option -%c requires an argument.\n", optopt);
412  }
413  else if (isprint (optopt))
414  {
415  fprintf (stderr, "Unknown option `-%c'.\n", optopt);
416  }
417  else
418  {
419  fprintf (stderr, "Unknown option character `\\x%x'.\n",optopt);
420  }
421  /* unknown or wrong option used, show usage information and terminate */
422  usage();
423  return -1;
424  }
425  default:
426  {
427  abort ();
428  return -1;//for parasoft
429  }
430  }
431 
432  /* Initialize DLT Client */
433  dlt_client_init(&dltclient, dltdata.vflag);
434 
435  /* Register callback to be called when message was received */
437 
438  /* Setup DLT Client structure */
439  dltclient.mode = dltdata.yflag;
440 
441  if (dltclient.mode==DLT_CLIENT_MODE_TCP)
442  {
443  for (index = optind; index < argc; index++)
444  {
445  if(dlt_client_set_server_ip(&dltclient, argv[index]) == -1)
446  {
447  fprintf(stderr,"set server ip didn't succeed\n");
448  return -1;
449  }
450  }
451 
452  if (dltclient.servIP == 0)
453  {
454  /* no hostname selected, show usage and terminate */
455  fprintf(stderr,"ERROR: No hostname selected\n");
456  usage();
457  dlt_client_cleanup(&dltclient,dltdata.vflag);
458  return -1;
459  }
460  }
461  else
462  {
463  for (index = optind; index < argc; index++)
464  {
465  if(dlt_client_set_serial_device(&dltclient, argv[index]) == -1)
466  {
467  fprintf(stderr,"set serial device didn't succeed\n");
468  return -1;
469  }
470  }
471 
472  if (dltclient.serialDevice == 0)
473  {
474  /* no serial device name selected, show usage and terminate */
475  fprintf(stderr,"ERROR: No serial device name specified\n");
476  usage();
477  return -1;
478  }
479 
480  dlt_client_setbaudrate(&dltclient,dltdata.bvalue);
481  }
482 
483  /* initialise structure to use DLT file */
484  dlt_file_init(&(dltdata.file),dltdata.vflag);
485 
486  /* first parse filter file if filter parameter is used */
487  dlt_filter_init(&(dltdata.filter),dltdata.vflag);
488 
489  if (dltdata.fvalue)
490  {
491  if (dlt_filter_load(&(dltdata.filter),dltdata.fvalue,dltdata.vflag) < DLT_RETURN_OK)
492  {
493  dlt_file_free(&(dltdata.file),dltdata.vflag);
494  return -1;
495  }
496 
497  dlt_file_set_filter(&(dltdata.file),&(dltdata.filter),dltdata.vflag);
498  }
499 
500  /* open DLT output file */
501  if (dltdata.ovalue)
502  {
503  if (dltdata.climit > -1)
504  {
505  char tmp[256];
506  snprintf(tmp, 256, "Using file size limit of %" PRId64 "bytes\n", dltdata.climit);
507  dlt_log(LOG_INFO, tmp);
508  dltdata.ohandle = dlt_receive_open_output_file(&dltdata);
509  }
510  else /* in case no limit for the output file is given, we simply overwrite any existing file */
511  {
512  dltdata.ohandle = open(dltdata.ovalue, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
513  }
514 
515  if (dltdata.ohandle == -1)
516  {
517  dlt_file_free(&(dltdata.file),dltdata.vflag);
518  fprintf(stderr,"ERROR: Output file %s cannot be opened!\n",dltdata.ovalue);
519  return -1;
520  }
521  }
522 
523  if (dltdata.evalue)
524  {
525  dlt_set_id(dltdata.ecuid,dltdata.evalue);
526  }
527  else
528  {
530  }
531 
532  /* Connect to TCP socket or open serial device */
533  if (dlt_client_connect(&dltclient, dltdata.vflag) != DLT_RETURN_ERROR)
534  {
535 
536  /* Dlt Client Main Loop */
537  dlt_client_main_loop(&dltclient, &dltdata, dltdata.vflag);
538 
539  /* Dlt Client Cleanup */
540  dlt_client_cleanup(&dltclient,dltdata.vflag);
541  }
542 
543  /* dlt-receive cleanup */
544  if (dltdata.ovalue)
545  {
546  close(dltdata.ohandle);
547  }
548 
549  free(dltdata.ovaluebase);
550 
551  dlt_file_free(&(dltdata.file),dltdata.vflag);
552 
553  dlt_filter_free(&(dltdata.filter),dltdata.vflag);
554 
555  return 0;
556 }
557 
559 {
560  DltReceiveData *dltdata;
561  static char text[DLT_RECEIVE_TEXTBUFSIZE];
562 
563  struct iovec iov[2];
564  int bytes_written;
565 
566  if ((message==0) || (data==0))
567  {
568  return -1;
569  }
570 
571  dltdata = (DltReceiveData*)data;
572 
573  /* prepare storage header */
574  if (DLT_IS_HTYP_WEID(message->standardheader->htyp))
575  {
576  dlt_set_storageheader(message->storageheader,message->headerextra.ecu);
577  }
578  else
579  {
580  dlt_set_storageheader(message->storageheader,dltdata->ecuid);
581  }
582 
583  if ((dltdata->fvalue==0) ||
584  (dltdata->fvalue && dlt_message_filter_check(message,&(dltdata->filter),dltdata->vflag) == DLT_RETURN_TRUE))
585  {
586  /* if no filter set or filter is matching display message */
587  if (dltdata->xflag)
588  {
589  dlt_message_print_hex(message,text,DLT_RECEIVE_TEXTBUFSIZE,dltdata->vflag);
590  }
591  else if (dltdata->aflag)
592  {
593 
594  dlt_message_header(message,text,DLT_RECEIVE_TEXTBUFSIZE,dltdata->vflag);
595 
596  printf("%s ",text);
597 
599 
600  printf("[%s]\n",text);
601  }
602  else if (dltdata->mflag)
603  {
605  }
606  else if (dltdata->sflag)
607  {
608 
609  dlt_message_header(message,text,DLT_RECEIVE_TEXTBUFSIZE,dltdata->vflag);
610 
611  printf("%s \n",text);
612  }
613 
614  /* if file output enabled write message */
615  if (dltdata->ovalue)
616  {
617  iov[0].iov_base = message->headerbuffer;
618  iov[0].iov_len = message->headersize;
619  iov[1].iov_base = message->databuffer;
620  iov[1].iov_len = message->datasize;
621 
622  if (dltdata->climit > -1)
623  {
624  int bytes_to_write = message->headersize + message->datasize;
625 
626  if ((bytes_to_write + dltdata->totalbytes > dltdata->climit))
627  {
629 
630  if (dlt_receive_open_output_file(dltdata) < 0)
631  {
632  printf("ERROR: dlt_receive_message_callback: Unable to open log when maximum filesize was reached!\n");
633  return -1;
634  }
635 
636  dltdata->totalbytes = 0;
637  }
638  }
639 
640  bytes_written = writev(dltdata->ohandle, iov, 2);
641 
642  dltdata->totalbytes += bytes_written;
643 
644  if (0 > bytes_written){
645  printf("dlt_receive_message_callback: writev(dltdata->ohandle, iov, 2); returned an error!" );
646  return -1;
647  }
648  }
649  }
650 
651  return 0;
652 }
int32_t datasize
Definition: dlt_common.h:423
DltStorageHeader * storageheader
Definition: dlt_common.h:432
void dlt_set_id(char *id, const char *text)
Definition: dlt_common.c:324
void dlt_client_register_message_callback(int(*registerd_callback)(DltMessage *message, void *data))
Definition: dlt_client.c:105
DltReturnValue dlt_file_set_filter(DltFile *file, DltFilter *filter, int verbose)
Definition: dlt_common.c:1331
#define DLT_RECEIVE_ECU_ID
Definition: dlt-receive.c:87
DltReturnValue dlt_client_main_loop(DltClient *client, void *data, int verbose)
Definition: dlt_client.c:326
int dlt_client_set_server_ip(DltClient *client, char *ipaddr)
Definition: dlt_client.c:839
void usage()
Definition: dlt-receive.c:116
int main(int argc, char *argv[])
Definition: dlt-receive.c:302
DltReturnValue dlt_message_filter_check(DltMessage *msg, DltFilter *filter, int verbose)
Definition: dlt_common.c:1057
int dlt_receive_message_callback(DltMessage *message, void *data)
Definition: dlt-receive.c:558
DltReturnValue dlt_log(int prio, char *s)
Definition: dlt_common.c:2029
DltReturnValue dlt_client_setbaudrate(DltClient *client, int baudrate)
Definition: dlt_client.c:827
DltReturnValue dlt_filter_init(DltFilter *filter, int verbose)
Definition: dlt_common.c:390
int dlt_client_set_serial_device(DltClient *client, char *serial_device)
Definition: dlt_client.c:850
static char data[kDataSize]
Definition: city-test.cc:40
DltReturnValue dlt_set_storageheader(DltStorageHeader *storageheader, const char *ecu)
Definition: dlt_common.c:2315
DltReturnValue dlt_client_init(DltClient *client, int verbose)
Definition: dlt_client.c:133
DltReturnValue dlt_filter_free(DltFilter *filter, int verbose)
Definition: dlt_common.c:404
DltReturnValue dlt_client_cleanup(DltClient *client, int verbose)
Definition: dlt_client.c:301
DltReturnValue dlt_client_connect(DltClient *client, int verbose)
Definition: dlt_client.c:168
DltReturnValue dlt_filter_load(DltFilter *filter, const char *filename, int verbose)
Definition: dlt_common.c:416
int32_t headersize
Definition: dlt_common.h:422
uint8_t headerbuffer[sizeof(DltStorageHeader)+sizeof(DltStandardHeader)+sizeof(DltStandardHeaderExtra)+sizeof(DltExtendedHeader)]
Definition: dlt_common.h:427
#define DLT_RECEIVE_TEXTBUFSIZE
Definition: dlt-receive.c:85
int64_t totalbytes
Definition: dlt-receive.c:107
#define DLT_IS_HTYP_WEID(htyp)
Definition: dlt_protocol.h:91
DltStandardHeaderExtra headerextra
Definition: dlt_common.h:434
char * ovaluebase
Definition: dlt-receive.c:100
DltReturnValue dlt_file_init(DltFile *file, int verbose)
Definition: dlt_common.c:1305
DltReturnValue dlt_message_payload(DltMessage *msg, char *text, int textlength, int type, int verbose)
Definition: dlt_common.c:891
int dlt_receive_open_output_file(DltReceiveData *dltdata)
Definition: dlt-receive.c:212
DltReturnValue dlt_file_free(DltFile *file, int verbose)
Definition: dlt_common.c:1942
DltFilter filter
Definition: dlt-control.c:129
DltStandardHeader * standardheader
Definition: dlt_common.h:433
void dlt_get_version(char *buf, size_t size)
Definition: dlt_common.c:3239
DltReturnValue dlt_message_header(DltMessage *msg, char *text, int textlength, int verbose)
Definition: dlt_common.c:710
int64_t convert_arg_to_byte_size(char *arg)
Definition: dlt-receive.c:144
int64_t climit
Definition: dlt-receive.c:104
DltReturnValue dlt_message_print_hex(DltMessage *message, char *text, uint32_t size, int verbose)
Definition: dlt_common.c:3310
char * servIP
Definition: dlt_client.h:93
#define DLT_OUTPUT_ASCII
Definition: dlt_common.h:271
uint8_t * databuffer
Definition: dlt_common.h:428
char * serialDevice
Definition: dlt_client.h:95
void dlt_receive_close_output_file(DltReceiveData *dltdata)
Definition: dlt-receive.c:289
DltClientMode mode
Definition: dlt_client.h:99
DltReturnValue dlt_message_print_mixed_plain(DltMessage *message, char *text, uint32_t size, int verbose)
Definition: dlt_common.c:3340
#define NULL
Definition: dlt_common.h:232